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
46 using namespace cv;
47 using namespace std;
48
49 namespace cvtest
50 {
51
fourccToString(int fourcc)52 string 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
58 const 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
86 const 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
104 class CV_VideoIOTest : public cvtest::BaseTest
105 {
106 protected:
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
CV_VideoIOTest()112 CV_VideoIOTest() {}
~CV_VideoIOTest()113 ~CV_VideoIOTest() {}
114 virtual void run(int) = 0;
115 };
116
117 class CV_ImageTest : public CV_VideoIOTest
118 {
119 public:
CV_ImageTest()120 CV_ImageTest() {}
~CV_ImageTest()121 ~CV_ImageTest() {}
122 void run(int);
123 };
124
125 class CV_SpecificImageTest : public CV_VideoIOTest
126 {
127 public:
CV_SpecificImageTest()128 CV_SpecificImageTest() {}
~CV_SpecificImageTest()129 ~CV_SpecificImageTest() {}
130 void run(int);
131 };
132
133 class CV_VideoTest : public CV_VideoIOTest
134 {
135 public:
CV_VideoTest()136 CV_VideoTest() {}
~CV_VideoTest()137 ~CV_VideoTest() {}
138 void run(int);
139 };
140
141 class CV_SpecificVideoTest : public CV_VideoIOTest
142 {
143 public:
CV_SpecificVideoTest()144 CV_SpecificVideoTest() {}
~CV_SpecificVideoTest()145 ~CV_SpecificVideoTest() {}
146 void run(int);
147 };
148
149
ImageTest(const string & dir)150 void 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
VideoTest(const string & dir,const cvtest::VideoFormat & fmt)256 void 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
SpecificImageTest(const string & dir)342 void 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
SpecificVideoTest(const string & dir,const cvtest::VideoFormat & fmt)428 void 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
run(int)546 void CV_ImageTest::run(int)
547 {
548 ImageTest(ts->get_data_path());
549 }
550
run(int)551 void CV_SpecificImageTest::run(int)
552 {
553 SpecificImageTest(ts->get_data_path());
554 }
555
run(int)556 void 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
run(int)567 void 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
TEST(Videoio_Image,regression)579 TEST(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__)
TEST(Videoio_Video,regression)583 TEST(Videoio_Video, regression) { CV_VideoTest test; test.safe_run(); }
TEST(Videoio_Video,write_read)584 TEST(Videoio_Video, write_read) { CV_SpecificVideoTest test; test.safe_run(); }
585 #endif
586
TEST(Videoio_Image,write_read)587 TEST(Videoio_Image, write_read) { CV_SpecificImageTest test; test.safe_run(); }
588