thread-safe VideoWriter and VideoCapture
This commit is contained in:
@@ -43,11 +43,12 @@
|
||||
#include "test_precomp.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
|
||||
using namespace cv;
|
||||
|
||||
#ifdef HAVE_FFMPEG
|
||||
|
||||
#include "ffmpeg_codecs.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
class CV_FFmpegWriteBigVideoTest : public cvtest::BaseTest
|
||||
@@ -118,11 +119,11 @@ public:
|
||||
else
|
||||
{
|
||||
Mat img(frame_s, CV_8UC3, Scalar::all(0));
|
||||
const int coeff = cvRound(cv::min(frame_s.width, frame_s.height)/(fps0 * time_sec));
|
||||
const int coeff = cvRound(min(frame_s.width, frame_s.height)/(fps0 * time_sec));
|
||||
|
||||
for (int i = 0 ; i < static_cast<int>(fps * time_sec); i++ )
|
||||
{
|
||||
//circle(img, Point2i(img_c / 2, img_r / 2), cv::min(img_r, img_c) / 2 * (i + 1), Scalar(255, 0, 0, 0), 2);
|
||||
//circle(img, Point2i(img_c / 2, img_r / 2), min(img_r, img_c) / 2 * (i + 1), Scalar(255, 0, 0, 0), 2);
|
||||
rectangle(img, Point2i(coeff * i, coeff * i), Point2i(coeff * (i + 1), coeff * (i + 1)),
|
||||
Scalar::all(255 * (1.0 - static_cast<double>(i) / (fps * time_sec * 2) )), -1);
|
||||
writer << img;
|
||||
@@ -174,3 +175,221 @@ public:
|
||||
TEST(Highgui_Video, ffmpeg_image) { CV_FFmpegReadImageTest test; test.safe_run(); }
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_FFMPEG) || defined(WIN32) || defined(_WIN32)
|
||||
|
||||
//////////////////////////////// Parallel VideoWriters and VideoCaptures ////////////////////////////////////
|
||||
|
||||
class CreateVideoWriterInvoker :
|
||||
public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
const static Size FrameSize;
|
||||
static std::string TmpDirectory;
|
||||
|
||||
CreateVideoWriterInvoker(std::vector<VideoWriter*>& _writers, std::vector<std::string>& _files) :
|
||||
ParallelLoopBody(), writers(&_writers), files(&_files)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void operator() (const Range& range) const
|
||||
{
|
||||
for (int i = range.start; i != range.end; ++i)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << i << ".avi";
|
||||
std::string fileName = tempfile(stream.str().c_str());
|
||||
|
||||
files->operator[](i) = fileName;
|
||||
writers->operator[](i) = new VideoWriter(fileName, CV_FOURCC('X','V','I','D'), 25.0f, FrameSize);
|
||||
|
||||
CV_Assert(writers->operator[](i)->isOpened());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::vector<VideoWriter*>* writers;
|
||||
std::vector<std::string>* files;
|
||||
};
|
||||
|
||||
std::string CreateVideoWriterInvoker::TmpDirectory;
|
||||
const Size CreateVideoWriterInvoker::FrameSize(1020, 900);
|
||||
|
||||
class WriteVideo_Invoker :
|
||||
public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
enum { FrameCount = 300 };
|
||||
|
||||
static const Scalar ObjectColor;
|
||||
static const Point Center;
|
||||
|
||||
WriteVideo_Invoker(const std::vector<VideoWriter*>& _writers) :
|
||||
ParallelLoopBody(), writers(&_writers)
|
||||
{
|
||||
}
|
||||
|
||||
static void GenerateFrame(Mat& frame, unsigned int i)
|
||||
{
|
||||
frame = Scalar::all(i % 255);
|
||||
|
||||
std::string text = to_string(i);
|
||||
putText(frame, text, Point(50, Center.y), FONT_HERSHEY_SIMPLEX, 5.0, ObjectColor, 5, CV_AA);
|
||||
circle(frame, Center, i + 2, ObjectColor, 2, CV_AA);
|
||||
}
|
||||
|
||||
virtual void operator() (const Range& range) const
|
||||
{
|
||||
CV_Assert((range.start + 1) == range.end);
|
||||
VideoWriter* writer = writers->operator[](range.start);
|
||||
CV_Assert(writer != NULL);
|
||||
CV_Assert(writer->isOpened());
|
||||
|
||||
Mat frame(CreateVideoWriterInvoker::FrameSize, CV_8UC3);
|
||||
for (unsigned int i = 0; i < FrameCount; ++i)
|
||||
{
|
||||
GenerateFrame(frame, i);
|
||||
writer->operator<< (frame);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::string to_string(unsigned int i)
|
||||
{
|
||||
std::stringstream stream(std::ios::out);
|
||||
stream << "frame #" << i;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<VideoWriter*>* writers;
|
||||
};
|
||||
|
||||
const Scalar WriteVideo_Invoker::ObjectColor(Scalar::all(0));
|
||||
const Point WriteVideo_Invoker::Center(CreateVideoWriterInvoker::FrameSize.height / 2,
|
||||
CreateVideoWriterInvoker::FrameSize.width / 2);
|
||||
|
||||
class CreateVideoCaptureInvoker :
|
||||
public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
CreateVideoCaptureInvoker(std::vector<VideoCapture*>& _readers, const std::vector<std::string>& _files) :
|
||||
ParallelLoopBody(), readers(&_readers), files(&_files)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void operator() (const Range& range) const
|
||||
{
|
||||
for (int i = range.start; i != range.end; ++i)
|
||||
{
|
||||
readers->operator[](i) = new VideoCapture(files->operator[](i));
|
||||
CV_Assert(readers->operator[](i)->isOpened());
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::vector<VideoCapture*>* readers;
|
||||
const std::vector<std::string>* files;
|
||||
};
|
||||
|
||||
class ReadImageAndTest :
|
||||
public ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
ReadImageAndTest(const std::vector<VideoCapture*>& _readers, cvtest::TS* _ts) :
|
||||
ParallelLoopBody(), readers(&_readers), ts(_ts)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void operator() (const Range& range) const
|
||||
{
|
||||
CV_Assert(range.start + 1 == range.end);
|
||||
VideoCapture* capture = readers->operator[](range.start);
|
||||
CV_Assert(capture != NULL);
|
||||
CV_Assert(capture->isOpened());
|
||||
|
||||
const static double eps = 23.0;
|
||||
unsigned int frameCount = static_cast<unsigned int>(capture->get(CV_CAP_PROP_FRAME_COUNT));
|
||||
CV_Assert(frameCount == WriteVideo_Invoker::FrameCount);
|
||||
Mat reference(CreateVideoWriterInvoker::FrameSize, CV_8UC3);
|
||||
|
||||
for (unsigned int i = 0; i < frameCount && next; ++i)
|
||||
{
|
||||
Mat actual;
|
||||
(*capture) >> actual;
|
||||
|
||||
WriteVideo_Invoker::GenerateFrame(reference, i);
|
||||
|
||||
EXPECT_EQ(reference.cols, actual.cols);
|
||||
EXPECT_EQ(reference.rows, actual.rows);
|
||||
EXPECT_EQ(reference.depth(), actual.depth());
|
||||
EXPECT_EQ(reference.channels(), actual.channels());
|
||||
|
||||
double psnr = PSNR(actual, reference);
|
||||
if (psnr < eps)
|
||||
{
|
||||
#define SUM cvtest::TS::SUMMARY
|
||||
ts->printf(SUM, "\nPSNR: %lf\n", psnr);
|
||||
ts->printf(SUM, "Video #: %d\n", range.start);
|
||||
ts->printf(SUM, "Frame #: %d\n", i);
|
||||
#undef SUM
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
|
||||
ts->set_gtest_status();
|
||||
|
||||
Mat diff;
|
||||
absdiff(actual, reference, diff);
|
||||
|
||||
EXPECT_EQ(countNonZero(diff.reshape(1) > 1), 0);
|
||||
|
||||
next = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool next;
|
||||
|
||||
private:
|
||||
const std::vector<VideoCapture*>* readers;
|
||||
cvtest::TS* ts;
|
||||
};
|
||||
|
||||
bool ReadImageAndTest::next;
|
||||
|
||||
TEST(Highgui_Video_parallel_writers_and_readers, accuracy)
|
||||
{
|
||||
const unsigned int threadsCount = 4;
|
||||
cvtest::TS* ts = cvtest::TS::ptr();
|
||||
|
||||
// creating VideoWriters
|
||||
std::vector<VideoWriter*> writers(threadsCount);
|
||||
Range range(0, threadsCount);
|
||||
std::vector<std::string> files(threadsCount);
|
||||
CreateVideoWriterInvoker invoker1(writers, files);
|
||||
parallel_for_(range, invoker1);
|
||||
|
||||
// write a video
|
||||
parallel_for_(range, WriteVideo_Invoker(writers));
|
||||
|
||||
// deleting the writers
|
||||
for (std::vector<VideoWriter*>::iterator i = writers.begin(), end = writers.end(); i != end; ++i)
|
||||
delete *i;
|
||||
writers.clear();
|
||||
|
||||
std::vector<VideoCapture*> readers(threadsCount);
|
||||
CreateVideoCaptureInvoker invoker2(readers, files);
|
||||
parallel_for_(range, invoker2);
|
||||
|
||||
ReadImageAndTest::next = true;
|
||||
|
||||
parallel_for_(range, ReadImageAndTest(readers, ts));
|
||||
|
||||
// deleting tmp video files
|
||||
for (std::vector<std::string>::const_iterator i = files.begin(), end = files.end(); i != end; ++i)
|
||||
{
|
||||
int code = remove(i->c_str());
|
||||
if (code == 1)
|
||||
std::cerr << "Couldn't delete " << *i << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user