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.hpp" 45 46 using namespace cv; 47 48 #ifdef HAVE_FFMPEG 49 50 using namespace std; 51 52 static const char* AVI_EXT = ".avi"; 53 static const char* MP4_EXT = ".mp4"; 54 55 class CV_FFmpegWriteBigVideoTest : public cvtest::BaseTest 56 { 57 struct TestFormatEntry { 58 int tag; 59 const char* ext; 60 bool required; 61 }; 62 63 static long int getFileSize(string filename) 64 { 65 FILE *p_file = NULL; 66 p_file = fopen(filename.c_str(), "rb"); 67 if (p_file == NULL) 68 return -1; 69 fseek(p_file, 0, SEEK_END); 70 long int size = ftell(p_file); 71 fclose(p_file); 72 return size; 73 } 74 public: 75 void run(int) 76 { 77 const int img_r = 4096; 78 const int img_c = 4096; 79 const double fps0 = 15; 80 const double time_sec = 1; 81 82 const TestFormatEntry entries[] = { 83 {0, AVI_EXT, true}, 84 //{VideoWriter::fourcc('D', 'I', 'V', '3'), AVI_EXT, true}, 85 //{VideoWriter::fourcc('D', 'I', 'V', 'X'), AVI_EXT, true}, 86 {VideoWriter::fourcc('D', 'X', '5', '0'), AVI_EXT, true}, 87 {VideoWriter::fourcc('F', 'L', 'V', '1'), AVI_EXT, true}, 88 {VideoWriter::fourcc('H', '2', '6', '1'), AVI_EXT, true}, 89 {VideoWriter::fourcc('H', '2', '6', '3'), AVI_EXT, true}, 90 {VideoWriter::fourcc('I', '4', '2', '0'), AVI_EXT, true}, 91 //{VideoWriter::fourcc('j', 'p', 'e', 'g'), AVI_EXT, true}, 92 {VideoWriter::fourcc('M', 'J', 'P', 'G'), AVI_EXT, true}, 93 {VideoWriter::fourcc('m', 'p', '4', 'v'), AVI_EXT, true}, 94 {VideoWriter::fourcc('M', 'P', 'E', 'G'), AVI_EXT, true}, 95 //{VideoWriter::fourcc('W', 'M', 'V', '1'), AVI_EXT, true}, 96 //{VideoWriter::fourcc('W', 'M', 'V', '2'), AVI_EXT, true}, 97 {VideoWriter::fourcc('X', 'V', 'I', 'D'), AVI_EXT, true}, 98 //{VideoWriter::fourcc('Y', 'U', 'Y', '2'), AVI_EXT, true}, 99 {VideoWriter::fourcc('H', '2', '6', '4'), MP4_EXT, false} 100 }; 101 102 const size_t n = sizeof(entries)/sizeof(entries[0]); 103 104 for (size_t j = 0; j < n; ++j) 105 { 106 int tag = entries[j].tag; 107 const char* ext = entries[j].ext; 108 string s = cv::format("%08x%s", tag, ext); 109 110 const string filename = tempfile(s.c_str()); 111 112 try 113 { 114 double fps = fps0; 115 Size frame_s = Size(img_c, img_r); 116 117 if( tag == VideoWriter::fourcc('H', '2', '6', '1') ) 118 frame_s = Size(352, 288); 119 else if( tag == VideoWriter::fourcc('H', '2', '6', '3') ) 120 frame_s = Size(704, 576); 121 /*else if( tag == CV_FOURCC('M', 'J', 'P', 'G') || 122 tag == CV_FOURCC('j', 'p', 'e', 'g') ) 123 frame_s = Size(1920, 1080);*/ 124 125 if( tag == VideoWriter::fourcc('M', 'P', 'E', 'G') ) 126 { 127 frame_s = Size(720, 576); 128 fps = 25; 129 } 130 131 VideoWriter writer(filename, tag, fps, frame_s); 132 133 if (writer.isOpened() == false) 134 { 135 fprintf(stderr, "\n\nFile name: %s\n", filename.c_str()); 136 fprintf(stderr, "Codec id: %d Codec tag: %c%c%c%c\n", (int)j, 137 tag & 255, (tag >> 8) & 255, (tag >> 16) & 255, (tag >> 24) & 255); 138 fprintf(stderr, "Error: cannot create video file."); 139 if (entries[j].required) 140 ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); 141 } 142 else 143 { 144 Mat img(frame_s, CV_8UC3, Scalar::all(0)); 145 const int coeff = cvRound(min(frame_s.width, frame_s.height)/(fps0 * time_sec)); 146 147 for (int i = 0 ; i < static_cast<int>(fps * time_sec); i++ ) 148 { 149 //circle(img, Point2i(img_c / 2, img_r / 2), min(img_r, img_c) / 2 * (i + 1), Scalar(255, 0, 0, 0), 2); 150 rectangle(img, Point2i(coeff * i, coeff * i), Point2i(coeff * (i + 1), coeff * (i + 1)), 151 Scalar::all(255 * (1.0 - static_cast<double>(i) / (fps * time_sec * 2) )), -1); 152 writer << img; 153 } 154 155 writer.release(); 156 long int sz = getFileSize(filename); 157 if (sz < 0) 158 { 159 fprintf(stderr, "ERROR: File name: %s was not created\n", filename.c_str()); 160 if (entries[j].required) 161 ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); 162 } 163 else 164 { 165 if (sz < 8192) 166 { 167 fprintf(stderr, "ERROR: File name: %s is very small (data write problems?)\n", filename.c_str()); 168 if (entries[j].required) 169 ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); 170 } 171 remove(filename.c_str()); 172 } 173 } 174 } 175 catch(...) 176 { 177 ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); 178 } 179 ts->set_failed_test_info(cvtest::TS::OK); 180 } 181 } 182 }; 183 184 TEST(Videoio_Video, ffmpeg_writebig) { CV_FFmpegWriteBigVideoTest test; test.safe_run(); } 185 186 class CV_FFmpegReadImageTest : public cvtest::BaseTest 187 { 188 public: 189 void run(int) 190 { 191 try 192 { 193 string filename = ts->get_data_path() + "readwrite/ordinary.bmp"; 194 VideoCapture cap(filename); 195 Mat img0 = imread(filename, 1); 196 Mat img, img_next; 197 cap >> img; 198 cap >> img_next; 199 200 CV_Assert( !img0.empty() && !img.empty() && img_next.empty() ); 201 202 double diff = cvtest::norm(img0, img, CV_C); 203 CV_Assert( diff == 0 ); 204 } 205 catch(...) 206 { 207 ts->set_failed_test_info(ts->FAIL_INVALID_OUTPUT); 208 } 209 ts->set_failed_test_info(cvtest::TS::OK); 210 } 211 }; 212 213 TEST(Videoio_Video, ffmpeg_image) { CV_FFmpegReadImageTest test; test.safe_run(); } 214 215 #endif 216 217 #if defined(HAVE_FFMPEG) 218 219 //////////////////////////////// Parallel VideoWriters and VideoCaptures //////////////////////////////////// 220 221 class CreateVideoWriterInvoker : 222 public ParallelLoopBody 223 { 224 public: 225 const static Size FrameSize; 226 static std::string TmpDirectory; 227 228 CreateVideoWriterInvoker(std::vector<VideoWriter*>& _writers, std::vector<std::string>& _files) : 229 ParallelLoopBody(), writers(&_writers), files(&_files) 230 { 231 } 232 233 virtual void operator() (const Range& range) const 234 { 235 for (int i = range.start; i != range.end; ++i) 236 { 237 std::ostringstream stream; 238 stream << i << ".avi"; 239 std::string fileName = tempfile(stream.str().c_str()); 240 241 files->operator[](i) = fileName; 242 writers->operator[](i) = new VideoWriter(fileName, VideoWriter::fourcc('X','V','I','D'), 25.0f, FrameSize); 243 244 CV_Assert(writers->operator[](i)->isOpened()); 245 } 246 } 247 248 private: 249 std::vector<VideoWriter*>* writers; 250 std::vector<std::string>* files; 251 }; 252 253 std::string CreateVideoWriterInvoker::TmpDirectory; 254 const Size CreateVideoWriterInvoker::FrameSize(1020, 900); 255 256 class WriteVideo_Invoker : 257 public ParallelLoopBody 258 { 259 public: 260 enum { FrameCount = 300 }; 261 262 static const Scalar ObjectColor; 263 static const Point Center; 264 265 WriteVideo_Invoker(const std::vector<VideoWriter*>& _writers) : 266 ParallelLoopBody(), writers(&_writers) 267 { 268 } 269 270 static void GenerateFrame(Mat& frame, unsigned int i) 271 { 272 frame = Scalar::all(i % 255); 273 274 std::string text = to_string(i); 275 putText(frame, text, Point(50, Center.y), FONT_HERSHEY_SIMPLEX, 5.0, ObjectColor, 5, CV_AA); 276 circle(frame, Center, i + 2, ObjectColor, 2, CV_AA); 277 } 278 279 virtual void operator() (const Range& range) const 280 { 281 for (int j = range.start; j < range.end; ++j) 282 { 283 VideoWriter* writer = writers->operator[](j); 284 CV_Assert(writer != NULL); 285 CV_Assert(writer->isOpened()); 286 287 Mat frame(CreateVideoWriterInvoker::FrameSize, CV_8UC3); 288 for (unsigned int i = 0; i < FrameCount; ++i) 289 { 290 GenerateFrame(frame, i); 291 writer->operator<< (frame); 292 } 293 } 294 } 295 296 protected: 297 static std::string to_string(unsigned int i) 298 { 299 std::stringstream stream(std::ios::out); 300 stream << "frame #" << i; 301 return stream.str(); 302 } 303 304 private: 305 const std::vector<VideoWriter*>* writers; 306 }; 307 308 const Scalar WriteVideo_Invoker::ObjectColor(Scalar::all(0)); 309 const Point WriteVideo_Invoker::Center(CreateVideoWriterInvoker::FrameSize.height / 2, 310 CreateVideoWriterInvoker::FrameSize.width / 2); 311 312 class CreateVideoCaptureInvoker : 313 public ParallelLoopBody 314 { 315 public: 316 CreateVideoCaptureInvoker(std::vector<VideoCapture*>& _readers, const std::vector<std::string>& _files) : 317 ParallelLoopBody(), readers(&_readers), files(&_files) 318 { 319 } 320 321 virtual void operator() (const Range& range) const 322 { 323 for (int i = range.start; i != range.end; ++i) 324 { 325 readers->operator[](i) = new VideoCapture(files->operator[](i)); 326 CV_Assert(readers->operator[](i)->isOpened()); 327 } 328 } 329 private: 330 std::vector<VideoCapture*>* readers; 331 const std::vector<std::string>* files; 332 }; 333 334 class ReadImageAndTest : 335 public ParallelLoopBody 336 { 337 public: 338 ReadImageAndTest(const std::vector<VideoCapture*>& _readers, cvtest::TS* _ts) : 339 ParallelLoopBody(), readers(&_readers), ts(_ts) 340 { 341 } 342 343 virtual void operator() (const Range& range) const 344 { 345 for (int j = range.start; j < range.end; ++j) 346 { 347 VideoCapture* capture = readers->operator[](j); 348 CV_Assert(capture != NULL); 349 CV_Assert(capture->isOpened()); 350 351 const static double eps = 23.0; 352 unsigned int frameCount = static_cast<unsigned int>(capture->get(CAP_PROP_FRAME_COUNT)); 353 CV_Assert(frameCount == WriteVideo_Invoker::FrameCount); 354 Mat reference(CreateVideoWriterInvoker::FrameSize, CV_8UC3); 355 356 for (unsigned int i = 0; i < frameCount && next; ++i) 357 { 358 Mat actual; 359 (*capture) >> actual; 360 361 WriteVideo_Invoker::GenerateFrame(reference, i); 362 363 EXPECT_EQ(reference.cols, actual.cols); 364 EXPECT_EQ(reference.rows, actual.rows); 365 EXPECT_EQ(reference.depth(), actual.depth()); 366 EXPECT_EQ(reference.channels(), actual.channels()); 367 368 double psnr = cvtest::PSNR(actual, reference); 369 if (psnr < eps) 370 { 371 #define SUM cvtest::TS::SUMMARY 372 ts->printf(SUM, "\nPSNR: %lf\n", psnr); 373 ts->printf(SUM, "Video #: %d\n", range.start); 374 ts->printf(SUM, "Frame #: %d\n", i); 375 #undef SUM 376 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 377 ts->set_gtest_status(); 378 379 Mat diff; 380 absdiff(actual, reference, diff); 381 382 EXPECT_EQ(countNonZero(diff.reshape(1) > 1), 0); 383 384 next = false; 385 } 386 } 387 } 388 } 389 390 static bool next; 391 392 private: 393 const std::vector<VideoCapture*>* readers; 394 cvtest::TS* ts; 395 }; 396 397 bool ReadImageAndTest::next; 398 399 TEST(Videoio_Video_parallel_writers_and_readers, accuracy) 400 { 401 const unsigned int threadsCount = 4; 402 cvtest::TS* ts = cvtest::TS::ptr(); 403 404 // creating VideoWriters 405 std::vector<VideoWriter*> writers(threadsCount); 406 Range range(0, threadsCount); 407 std::vector<std::string> files(threadsCount); 408 CreateVideoWriterInvoker invoker1(writers, files); 409 parallel_for_(range, invoker1); 410 411 // write a video 412 parallel_for_(range, WriteVideo_Invoker(writers)); 413 414 // deleting the writers 415 for (std::vector<VideoWriter*>::iterator i = writers.begin(), end = writers.end(); i != end; ++i) 416 delete *i; 417 writers.clear(); 418 419 std::vector<VideoCapture*> readers(threadsCount); 420 CreateVideoCaptureInvoker invoker2(readers, files); 421 parallel_for_(range, invoker2); 422 423 ReadImageAndTest::next = true; 424 425 parallel_for_(range, ReadImageAndTest(readers, ts)); 426 427 // deleting tmp video files 428 for (std::vector<std::string>::const_iterator i = files.begin(), end = files.end(); i != end; ++i) 429 { 430 int code = remove(i->c_str()); 431 if (code == 1) 432 std::cerr << "Couldn't delete " << *i << std::endl; 433 } 434 } 435 436 #endif 437