1/*M/////////////////////////////////////////////////////////////////////////////////////// 2// 3// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4// 5// By downloading, copying, installing or using the software you agree to this license. 6// If you do not agree to this license, do not download, install, 7// copy or use the software. 8// 9// 10// License Agreement 11// For Open Source Computer Vision Library 12// 13// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 14// Copyright (C) 2009, Willow Garage Inc., all rights reserved. 15// Third party copyrights are property of their respective owners. 16// 17// Redistribution and use in source and binary forms, with or without modification, 18// are permitted provided that the following conditions are met: 19// 20// * Redistribution's of source code must retain the above copyright notice, 21// this list of conditions and the following disclaimer. 22// 23// * Redistribution's in binary form must reproduce the above copyright notice, 24// this list of conditions and the following disclaimer in the documentation 25// and/or other materials provided with the distribution. 26// 27// * The name of the copyright holders may not be used to endorse or promote products 28// derived from this software without specific prior written permission. 29// 30// This software is provided by the copyright holders and contributors "as is" and 31// any express or implied warranties, including, but not limited to, the implied 32// warranties of merchantability and fitness for a particular purpose are disclaimed. 33// In no event shall the Intel Corporation or contributors be liable for any direct, 34// indirect, incidental, special, exemplary, or consequential damages 35// (including, but not limited to, procurement of substitute goods or services; 36// loss of use, data, or profits; or business interruption) however caused 37// and on any theory of liability, whether in contract, strict liability, 38// or tort (including negligence or otherwise) arising in any way out of 39// the use of this software, even if advised of the possibility of such damage. 40// 41//M*/ 42 43#include "test_precomp.hpp" 44#include "opencv2/videoio/videoio_c.h" 45 46using namespace cv; 47using namespace std; 48 49namespace cvtest 50{ 51 52string fourccToString(int fourcc) 53{ 54 return format("%c%c%c%c", fourcc & 255, (fourcc >> 8) & 255, (fourcc >> 16) & 255, (fourcc >> 24) & 255); 55} 56 57#ifdef HAVE_MSMF 58const VideoFormat g_specific_fmt_list[] = 59{ 60 /*VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', '2', '5')), 61 VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', '5', '0')), 62 VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 'c', ' ')), 63 VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 'h', '1')), 64 VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 'h', 'd')), 65 VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 's', 'd')), 66 VideoFormat("wmv", CV_FOURCC_MACRO('d', 'v', 's', 'l')), 67 VideoFormat("wmv", CV_FOURCC_MACRO('H', '2', '6', '3')), 68 VideoFormat("wmv", CV_FOURCC_MACRO('M', '4', 'S', '2')), 69 VideoFormat("avi", CV_FOURCC_MACRO('M', 'J', 'P', 'G')), 70 VideoFormat("mp4", CV_FOURCC_MACRO('M', 'P', '4', 'S')), 71 VideoFormat("mp4", CV_FOURCC_MACRO('M', 'P', '4', 'V')), 72 VideoFormat("wmv", CV_FOURCC_MACRO('M', 'P', '4', '3')), 73 VideoFormat("wmv", CV_FOURCC_MACRO('M', 'P', 'G', '1')), 74 VideoFormat("wmv", CV_FOURCC_MACRO('M', 'S', 'S', '1')), 75 VideoFormat("wmv", CV_FOURCC_MACRO('M', 'S', 'S', '2')),*/ 76#if !defined(_M_ARM) 77 VideoFormat("wmv", CV_FOURCC_MACRO('W', 'M', 'V', '1')), 78 VideoFormat("wmv", CV_FOURCC_MACRO('W', 'M', 'V', '2')), 79#endif 80 VideoFormat("wmv", CV_FOURCC_MACRO('W', 'M', 'V', '3')), 81 VideoFormat("avi", CV_FOURCC_MACRO('H', '2', '6', '4')), 82 //VideoFormat("wmv", CV_FOURCC_MACRO('W', 'V', 'C', '1')), 83 VideoFormat() 84}; 85#else 86const VideoFormat g_specific_fmt_list[] = 87{ 88 VideoFormat("avi", VideoWriter::fourcc('X', 'V', 'I', 'D')), 89 VideoFormat("avi", VideoWriter::fourcc('M', 'P', 'E', 'G')), 90 VideoFormat("avi", VideoWriter::fourcc('M', 'J', 'P', 'G')), 91 //VideoFormat("avi", VideoWriter::fourcc('I', 'Y', 'U', 'V')), 92 VideoFormat("mkv", VideoWriter::fourcc('X', 'V', 'I', 'D')), 93 VideoFormat("mkv", VideoWriter::fourcc('M', 'P', 'E', 'G')), 94 VideoFormat("mkv", VideoWriter::fourcc('M', 'J', 'P', 'G')), 95#ifndef HAVE_GSTREAMER 96 VideoFormat("mov", VideoWriter::fourcc('m', 'p', '4', 'v')), 97#endif 98 VideoFormat() 99}; 100#endif 101 102} 103 104class CV_VideoIOTest : public cvtest::BaseTest 105{ 106protected: 107 void ImageTest (const string& dir); 108 void VideoTest (const string& dir, const cvtest::VideoFormat& fmt); 109 void SpecificImageTest (const string& dir); 110 void SpecificVideoTest (const string& dir, const cvtest::VideoFormat& fmt); 111 112 CV_VideoIOTest() {} 113 ~CV_VideoIOTest() {} 114 virtual void run(int) = 0; 115}; 116 117class CV_ImageTest : public CV_VideoIOTest 118{ 119public: 120 CV_ImageTest() {} 121 ~CV_ImageTest() {} 122 void run(int); 123}; 124 125class CV_SpecificImageTest : public CV_VideoIOTest 126{ 127public: 128 CV_SpecificImageTest() {} 129 ~CV_SpecificImageTest() {} 130 void run(int); 131}; 132 133class CV_VideoTest : public CV_VideoIOTest 134{ 135public: 136 CV_VideoTest() {} 137 ~CV_VideoTest() {} 138 void run(int); 139}; 140 141class CV_SpecificVideoTest : public CV_VideoIOTest 142{ 143public: 144 CV_SpecificVideoTest() {} 145 ~CV_SpecificVideoTest() {} 146 void run(int); 147}; 148 149 150void CV_VideoIOTest::ImageTest(const string& dir) 151{ 152 string _name = dir + string("../cv/shared/baboon.png"); 153 ts->printf(ts->LOG, "reading image : %s\n", _name.c_str()); 154 155 Mat image = imread(_name); 156 image.convertTo(image, CV_8UC3); 157 158 if (image.empty()) 159 { 160 ts->set_failed_test_info(ts->FAIL_MISSING_TEST_DATA); 161 return; 162 } 163 164 const string exts[] = { 165#ifdef HAVE_PNG 166 "png", 167#endif 168#ifdef HAVE_TIFF 169 "tiff", 170#endif 171#ifdef HAVE_JPEG 172 "jpg", 173#endif 174#ifdef HAVE_JASPER 175 "jp2", 176#endif 177#if 0 /*defined HAVE_OPENEXR && !defined __APPLE__*/ 178 "exr", 179#endif 180 "bmp", 181 "ppm", 182 "ras" 183 }; 184 const size_t ext_num = sizeof(exts)/sizeof(exts[0]); 185 186 for(size_t i = 0; i < ext_num; ++i) 187 { 188 string ext = exts[i]; 189 string full_name = cv::tempfile(ext.c_str()); 190 ts->printf(ts->LOG, " full_name : %s\n", full_name.c_str()); 191 192 imwrite(full_name, image); 193 194 Mat loaded = imread(full_name); 195 if (loaded.empty()) 196 { 197 ts->printf(ts->LOG, "Reading failed at fmt=%s\n", ext.c_str()); 198 ts->set_failed_test_info(ts->FAIL_MISMATCH); 199 continue; 200 } 201 202 const double thresDbell = 20; 203 double psnr = cvtest::PSNR(loaded, image); 204 if (psnr < thresDbell) 205 { 206 ts->printf(ts->LOG, "Reading image from file: too big difference (=%g) with fmt=%s\n", psnr, ext.c_str()); 207 ts->set_failed_test_info(ts->FAIL_BAD_ACCURACY); 208 continue; 209 } 210 211 vector<uchar> from_file; 212 213 FILE *f = fopen(full_name.c_str(), "rb"); 214 fseek(f, 0, SEEK_END); 215 long len = ftell(f); 216 from_file.resize((size_t)len); 217 fseek(f, 0, SEEK_SET); 218 from_file.resize(fread(&from_file[0], 1, from_file.size(), f)); 219 fclose(f); 220 221 vector<uchar> buf; 222 imencode("." + exts[i], image, buf); 223 224 if (buf != from_file) 225 { 226 ts->printf(ts->LOG, "Encoding failed with fmt=%s\n", ext.c_str()); 227 ts->set_failed_test_info(ts->FAIL_MISMATCH); 228 continue; 229 } 230 231 Mat buf_loaded = imdecode(Mat(buf), 1); 232 233 if (buf_loaded.empty()) 234 { 235 ts->printf(ts->LOG, "Decoding failed with fmt=%s\n", ext.c_str()); 236 ts->set_failed_test_info(ts->FAIL_MISMATCH); 237 continue; 238 } 239 240 psnr = cvtest::PSNR(buf_loaded, image); 241 242 if (psnr < thresDbell) 243 { 244 ts->printf(ts->LOG, "Decoding image from memory: too small PSNR (=%gdb) with fmt=%s\n", psnr, ext.c_str()); 245 ts->set_failed_test_info(ts->FAIL_MISMATCH); 246 continue; 247 } 248 249 } 250 251 ts->printf(ts->LOG, "end test function : ImagesTest \n"); 252 ts->set_failed_test_info(ts->OK); 253} 254 255 256void CV_VideoIOTest::VideoTest(const string& dir, const cvtest::VideoFormat& fmt) 257{ 258 string src_file = dir + "../cv/shared/video_for_test.avi"; 259 string tmp_name = cv::tempfile((cvtest::fourccToString(fmt.fourcc) + "." + fmt.ext).c_str()); 260 261 ts->printf(ts->LOG, "reading video : %s and converting it to %s\n", src_file.c_str(), tmp_name.c_str()); 262 263 CvCapture* cap = cvCaptureFromFile(src_file.c_str()); 264 265 if (!cap) 266 { 267 ts->set_failed_test_info(ts->FAIL_MISMATCH); 268 return; 269 } 270 271 CvVideoWriter* writer = 0; 272 vector<Mat> frames; 273 274 for(;;) 275 { 276 IplImage* img = cvQueryFrame( cap ); 277 278 if (!img) 279 break; 280 281 frames.push_back(cv::cvarrToMat(img, true)); 282 283 if (writer == NULL) 284 { 285 writer = cvCreateVideoWriter(tmp_name.c_str(), fmt.fourcc, 24, cvGetSize(img)); 286 if (writer == NULL) 287 { 288 ts->printf(ts->LOG, "can't create writer (with fourcc : %s)\n", 289 cvtest::fourccToString(fmt.fourcc).c_str()); 290 cvReleaseCapture( &cap ); 291 ts->set_failed_test_info(ts->FAIL_MISMATCH); 292 return; 293 } 294 } 295 296 cvWriteFrame(writer, img); 297 } 298 299 cvReleaseVideoWriter( &writer ); 300 cvReleaseCapture( &cap ); 301 302 CvCapture *saved = cvCaptureFromFile(tmp_name.c_str()); 303 if (!saved) 304 { 305 ts->set_failed_test_info(ts->FAIL_MISMATCH); 306 return; 307 } 308 309 const double thresDbell = 20; 310 311 for(int i = 0;; i++) 312 { 313 IplImage* ipl1 = cvQueryFrame( saved ); 314 315 if (!ipl1) 316 break; 317 318 Mat img = frames[i]; 319 Mat img1 = cv::cvarrToMat(ipl1); 320 321 double psnr = cvtest::PSNR(img1, img); 322 if (psnr < thresDbell) 323 { 324 ts->printf(ts->LOG, "Too low frame %d psnr = %gdb\n", i, psnr); 325 ts->set_failed_test_info(ts->FAIL_MISMATCH); 326 327 //imwrite("original.png", img); 328 //imwrite("after_test.png", img1); 329 //Mat diff; 330 //absdiff(img, img1, diff); 331 //imwrite("diff.png", diff); 332 333 break; 334 } 335 } 336 337 cvReleaseCapture( &saved ); 338 339 ts->printf(ts->LOG, "end test function : ImagesVideo \n"); 340} 341 342void CV_VideoIOTest::SpecificImageTest(const string& dir) 343{ 344 const size_t IMAGE_COUNT = 10; 345 346 for (size_t i = 0; i < IMAGE_COUNT; ++i) 347 { 348 stringstream s; s << i; 349 string file_path = dir+"../python/images/QCIF_0"+s.str()+".bmp"; 350 Mat image = imread(file_path); 351 352 if (image.empty()) 353 { 354 ts->set_failed_test_info(ts->FAIL_MISSING_TEST_DATA); 355 return; 356 } 357 358 resize(image, image, Size(968, 757), 0.0, 0.0, INTER_CUBIC); 359 360 stringstream s_digit; s_digit << i; 361 362 string full_name = cv::tempfile((s_digit.str() + ".bmp").c_str()); 363 ts->printf(ts->LOG, " full_name : %s\n", full_name.c_str()); 364 365 imwrite(full_name, image); 366 367 Mat loaded = imread(full_name); 368 if (loaded.empty()) 369 { 370 ts->printf(ts->LOG, "Reading failed at fmt=bmp\n"); 371 ts->set_failed_test_info(ts->FAIL_MISMATCH); 372 continue; 373 } 374 375 const double thresDbell = 20; 376 double psnr = cvtest::PSNR(loaded, image); 377 if (psnr < thresDbell) 378 { 379 ts->printf(ts->LOG, "Reading image from file: too big difference (=%g) with fmt=bmp\n", psnr); 380 ts->set_failed_test_info(ts->FAIL_BAD_ACCURACY); 381 continue; 382 } 383 384 vector<uchar> from_file; 385 386 FILE *f = fopen(full_name.c_str(), "rb"); 387 fseek(f, 0, SEEK_END); 388 long len = ftell(f); 389 from_file.resize((size_t)len); 390 fseek(f, 0, SEEK_SET); 391 from_file.resize(fread(&from_file[0], 1, from_file.size(), f)); 392 fclose(f); 393 394 vector<uchar> buf; 395 imencode(".bmp", image, buf); 396 397 if (buf != from_file) 398 { 399 ts->printf(ts->LOG, "Encoding failed with fmt=bmp\n"); 400 ts->set_failed_test_info(ts->FAIL_MISMATCH); 401 continue; 402 } 403 404 Mat buf_loaded = imdecode(Mat(buf), 1); 405 406 if (buf_loaded.empty()) 407 { 408 ts->printf(ts->LOG, "Decoding failed with fmt=bmp\n"); 409 ts->set_failed_test_info(ts->FAIL_MISMATCH); 410 continue; 411 } 412 413 psnr = cvtest::PSNR(buf_loaded, image); 414 415 if (psnr < thresDbell) 416 { 417 ts->printf(ts->LOG, "Decoding image from memory: too small PSNR (=%gdb) with fmt=bmp\n", psnr); 418 ts->set_failed_test_info(ts->FAIL_MISMATCH); 419 continue; 420 } 421 } 422 423 ts->printf(ts->LOG, "end test function : SpecificImageTest \n"); 424 ts->set_failed_test_info(ts->OK); 425} 426 427 428void CV_VideoIOTest::SpecificVideoTest(const string& dir, const cvtest::VideoFormat& fmt) 429{ 430 string ext = fmt.ext; 431 int fourcc = fmt.fourcc; 432 433 string fourcc_str = cvtest::fourccToString(fourcc); 434 const string video_file = cv::tempfile((fourcc_str + "." + ext).c_str()); 435 436 Size frame_size(968 & -2, 757 & -2); 437 VideoWriter writer(video_file, fourcc, 25, frame_size, true); 438 439 if (!writer.isOpened()) 440 { 441 // call it repeatedly for easier debugging 442 VideoWriter writer2(video_file, fourcc, 25, frame_size, true); 443 ts->printf(ts->LOG, "Creating a video in %s...\n", video_file.c_str()); 444 ts->printf(ts->LOG, "Cannot create VideoWriter object with codec %s.\n", fourcc_str.c_str()); 445 ts->set_failed_test_info(ts->FAIL_MISMATCH); 446 return; 447 } 448 449 const size_t IMAGE_COUNT = 30; 450 vector<Mat> images; 451 452 for( size_t i = 0; i < IMAGE_COUNT; ++i ) 453 { 454 string file_path = format("%s../python/images/QCIF_%02d.bmp", dir.c_str(), i); 455 Mat img = imread(file_path, IMREAD_COLOR); 456 457 if (img.empty()) 458 { 459 ts->printf(ts->LOG, "Creating a video in %s...\n", video_file.c_str()); 460 ts->printf(ts->LOG, "Error: cannot read frame from %s.\n", file_path.c_str()); 461 ts->printf(ts->LOG, "Continue creating the video file...\n"); 462 ts->set_failed_test_info(ts->FAIL_INVALID_TEST_DATA); 463 break; 464 } 465 466 for (int k = 0; k < img.rows; ++k) 467 for (int l = 0; l < img.cols; ++l) 468 if (img.at<Vec3b>(k, l) == Vec3b::all(0)) 469 img.at<Vec3b>(k, l) = Vec3b(0, 255, 0); 470 else img.at<Vec3b>(k, l) = Vec3b(0, 0, 255); 471 472 resize(img, img, frame_size, 0.0, 0.0, INTER_CUBIC); 473 474 images.push_back(img); 475 writer << img; 476 } 477 478 writer.release(); 479 VideoCapture cap(video_file); 480 481 size_t FRAME_COUNT = (size_t)cap.get(CAP_PROP_FRAME_COUNT); 482 483 size_t allowed_extra_frames = 0; 484 485 // Hack! Newer FFmpeg versions in this combination produce a file 486 // whose reported duration is one frame longer than needed, and so 487 // the calculated frame count is also off by one. Ideally, we'd want 488 // to fix both writing (to produce the correct duration) and reading 489 // (to correctly report frame count for such files), but I don't know 490 // how to do either, so this is a workaround for now. 491 // See also the same hack in CV_PositioningTest::run. 492 if (fourcc == VideoWriter::fourcc('M', 'P', 'E', 'G') && ext == "mkv") 493 allowed_extra_frames = 1; 494 495 // Hack! Some GStreamer encoding pipelines drop last frame in the video 496 int allowed_frame_frop = 0; 497#ifdef HAVE_GSTREAMER 498 allowed_frame_frop = 1; 499#endif 500 501 if (FRAME_COUNT < IMAGE_COUNT - allowed_frame_frop || FRAME_COUNT > IMAGE_COUNT + allowed_extra_frames) 502 { 503 ts->printf(ts->LOG, "\nFrame count checking for video_%s.%s...\n", fourcc_str.c_str(), ext.c_str()); 504 ts->printf(ts->LOG, "Video codec: %s\n", fourcc_str.c_str()); 505 if (allowed_extra_frames != 0) 506 ts->printf(ts->LOG, "Required frame count: %d-%d; Returned frame count: %d\n", 507 IMAGE_COUNT, IMAGE_COUNT + allowed_extra_frames, FRAME_COUNT); 508 else 509 ts->printf(ts->LOG, "Required frame count: %d; Returned frame count: %d\n", IMAGE_COUNT, FRAME_COUNT); 510 ts->printf(ts->LOG, "Error: Incorrect frame count in the video.\n"); 511 ts->printf(ts->LOG, "Continue checking...\n"); 512 ts->set_failed_test_info(ts->FAIL_BAD_ACCURACY); 513 return; 514 } 515 516 for (int i = 0; (size_t)i < IMAGE_COUNT-allowed_frame_frop; i++) 517 { 518 Mat frame; cap >> frame; 519 if (frame.empty()) 520 { 521 ts->printf(ts->LOG, "\nVideo file directory: %s\n", "."); 522 ts->printf(ts->LOG, "File name: video_%s.%s\n", fourcc_str.c_str(), ext.c_str()); 523 ts->printf(ts->LOG, "Video codec: %s\n", fourcc_str.c_str()); 524 ts->printf(ts->LOG, "Error: cannot read the next frame with index %d.\n", i+1); 525 ts->set_failed_test_info(ts->FAIL_MISSING_TEST_DATA); 526 break; 527 } 528 529 Mat img = images[i]; 530 531 const double thresDbell = 40; 532 double psnr = cvtest::PSNR(img, frame); 533 534 if (psnr > thresDbell) 535 { 536 ts->printf(ts->LOG, "\nReading frame from the file video_%s.%s...\n", fourcc_str.c_str(), ext.c_str()); 537 ts->printf(ts->LOG, "Frame index: %d\n", i+1); 538 ts->printf(ts->LOG, "Difference between saved and original images: %g\n", psnr); 539 ts->printf(ts->LOG, "Maximum allowed difference: %g\n", thresDbell); 540 ts->printf(ts->LOG, "Error: too big difference between saved and original images.\n"); 541 break; 542 } 543 } 544} 545 546void CV_ImageTest::run(int) 547{ 548 ImageTest(ts->get_data_path()); 549} 550 551void CV_SpecificImageTest::run(int) 552{ 553 SpecificImageTest(ts->get_data_path()); 554} 555 556void CV_VideoTest::run(int) 557{ 558 for (int i = 0; ; ++i) 559 { 560 const cvtest::VideoFormat& fmt = cvtest::g_specific_fmt_list[i]; 561 if( fmt.empty() ) 562 break; 563 VideoTest(ts->get_data_path(), fmt); 564 } 565} 566 567void CV_SpecificVideoTest::run(int) 568{ 569 for (int i = 0; ; ++i) 570 { 571 const cvtest::VideoFormat& fmt = cvtest::g_specific_fmt_list[i]; 572 if( fmt.empty() ) 573 break; 574 SpecificVideoTest(ts->get_data_path(), fmt); 575 } 576} 577 578#ifdef HAVE_JPEG 579TEST(Videoio_Image, regression) { CV_ImageTest test; test.safe_run(); } 580#endif 581 582#if BUILD_WITH_VIDEO_INPUT_SUPPORT && BUILD_WITH_VIDEO_OUTPUT_SUPPORT && !defined(__APPLE__) 583TEST(Videoio_Video, regression) { CV_VideoTest test; test.safe_run(); } 584TEST(Videoio_Video, write_read) { CV_SpecificVideoTest test; test.safe_run(); } 585#endif 586 587TEST(Videoio_Image, write_read) { CV_SpecificImageTest test; test.safe_run(); } 588