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