12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010 |
- /*M///////////////////////////////////////////////////////////////////////////////////////
- //
- // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
- //
- // By downloading, copying, installing or using the software you agree to this license.
- // If you do not agree to this license, do not download, install,
- // copy or use the software.
- //
- //
- // License Agreement
- // For Open Source Computer Vision Library
- //
- // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
- // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
- // Third party copyrights are property of their respective owners.
- //
- // Redistribution and use in source and binary forms, with or without modification,
- // are permitted provided that the following conditions are met:
- //
- // * Redistribution's of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- //
- // * Redistribution's in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- //
- // * The name of the copyright holders may not be used to endorse or promote products
- // derived from this software without specific prior written permission.
- //
- // This software is provided by the copyright holders and contributors "as is" and
- // any express or implied warranties, including, but not limited to, the implied
- // warranties of merchantability and fitness for a particular purpose are disclaimed.
- // In no event shall the Intel Corporation or contributors be liable for any direct,
- // indirect, incidental, special, exemplary, or consequential damages
- // (including, but not limited to, procurement of substitute goods or services;
- // loss of use, data, or profits; or business interruption) however caused
- // and on any theory of liability, whether in contract, strict liability,
- // or tort (including negligence or otherwise) arising in any way out of
- // the use of this software, even if advised of the possibility of such damage.
- //
- //M*/
- #include "test_precomp.hpp"
- #include "opencv2/videoio/videoio_c.h"
- namespace opencv_test
- {
- class Videoio_Test_Base
- {
- protected:
- string ext;
- string video_file;
- VideoCaptureAPIs apiPref;
- protected:
- Videoio_Test_Base() {}
- virtual ~Videoio_Test_Base() {}
- virtual void writeVideo() {}
- virtual void checkFrameContent(Mat &, int) {}
- virtual void checkFrameCount(int &) {}
- void checkFrameRead(int idx, VideoCapture & cap)
- {
- //int frameID = (int)cap.get(CAP_PROP_POS_FRAMES);
- Mat img;
- ASSERT_NO_THROW(cap >> img);
- //std::cout << "idx=" << idx << " img=" << img.size() << " frameID=" << frameID << std::endl;
- ASSERT_FALSE(img.empty()) << "idx=" << idx;
- checkFrameContent(img, idx);
- }
- void checkFrameSeek(int idx, VideoCapture & cap)
- {
- bool canSeek = false;
- ASSERT_NO_THROW(canSeek = cap.set(CAP_PROP_POS_FRAMES, idx));
- if (!canSeek)
- {
- std::cout << "Seek to frame '" << idx << "' is not supported. SKIP." << std::endl;
- return;
- }
- EXPECT_EQ(idx, (int)cap.get(CAP_PROP_POS_FRAMES));
- checkFrameRead(idx, cap);
- }
- public:
- void doTest()
- {
- if (!videoio_registry::hasBackend(apiPref))
- throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
- if (cvtest::skipUnstableTests && apiPref == CAP_MSMF && (ext == "h264" || ext == "h265" || ext == "mpg"))
- throw SkipTestException("Unstable MSMF test");
- writeVideo();
- VideoCapture cap;
- ASSERT_NO_THROW(cap.open(video_file, apiPref));
- if (!cap.isOpened())
- {
- std::cout << "SKIP test: backend " << apiPref << " can't open the video: " << video_file << std::endl;
- return;
- }
- int n_frames = -1;
- EXPECT_NO_THROW(n_frames = (int)cap.get(CAP_PROP_FRAME_COUNT));
- if (n_frames > 0)
- {
- ASSERT_GT(n_frames, 0);
- checkFrameCount(n_frames);
- }
- else
- {
- std::cout << "CAP_PROP_FRAME_COUNT is not supported by backend. Assume 50 frames." << std::endl;
- n_frames = 50;
- }
- {
- SCOPED_TRACE("consecutive read");
- if (apiPref == CAP_GSTREAMER)
- {
- // This workaround is for GStreamer 1.3.1.1 and older.
- // Old Gstreamer has a bug which handles the total duration 1 frame shorter
- // Old Gstreamer are used in Ubuntu 14.04, so the following code could be removed after it's EOL
- n_frames--;
- }
- for (int k = 0; k < n_frames; ++k)
- {
- checkFrameRead(k, cap);
- if (::testing::Test::HasFailure() && k % 10 == 0)
- break;
- }
- }
- bool canSeek = false;
- EXPECT_NO_THROW(canSeek = cap.set(CAP_PROP_POS_FRAMES, 0));
- if (!canSeek)
- {
- std::cout << "Seek to frame '0' is not supported. SKIP all 'seek' tests." << std::endl;
- return;
- }
- if (ext != "wmv" && ext != "h264" && ext != "h265")
- {
- SCOPED_TRACE("progressive seek");
- bool res = false;
- EXPECT_NO_THROW(res = cap.set(CAP_PROP_POS_FRAMES, 0));
- ASSERT_TRUE(res);
- for (int k = 0; k < n_frames; k += 20)
- {
- checkFrameSeek(k, cap);
- if (::testing::Test::HasFailure() && k % 10 == 0)
- break;
- }
- }
- if (ext != "mpg" && ext != "wmv" && ext != "h264" && ext != "h265")
- {
- SCOPED_TRACE("random seek");
- bool res = false;
- EXPECT_NO_THROW(res = cap.set(CAP_PROP_POS_FRAMES, 0));
- ASSERT_TRUE(res);
- for (int k = 0; k < 10; ++k)
- {
- checkFrameSeek(cvtest::TS::ptr()->get_rng().uniform(0, n_frames), cap);
- if (::testing::Test::HasFailure() && k % 10 == 0)
- break;
- }
- }
- }
- };
- //==================================================================================================
- typedef tuple<string, VideoCaptureAPIs> Backend_Type_Params;
- class videoio_bunny : public Videoio_Test_Base, public testing::TestWithParam<Backend_Type_Params>
- {
- BunnyParameters bunny_param;
- public:
- videoio_bunny()
- {
- ext = get<0>(GetParam());
- apiPref = get<1>(GetParam());
- video_file = BunnyParameters::getFilename(String(".") + ext);
- }
- void doFrameCountTest()
- {
- if (!videoio_registry::hasBackend(apiPref))
- throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
- if (cvtest::skipUnstableTests && apiPref == CAP_MSMF && (ext == "h264" || ext == "h265" || ext == "mpg"))
- throw SkipTestException("Unstable MSMF test");
- VideoCapture cap;
- EXPECT_NO_THROW(cap.open(video_file, apiPref));
- if (!cap.isOpened())
- {
- std::cout << "SKIP test: backend " << apiPref << " can't open the video: " << video_file << std::endl;
- return;
- }
- Size actual;
- EXPECT_NO_THROW(actual = Size((int)cap.get(CAP_PROP_FRAME_WIDTH),
- (int)cap.get(CAP_PROP_FRAME_HEIGHT)));
- EXPECT_EQ(bunny_param.getWidth(), actual.width);
- EXPECT_EQ(bunny_param.getHeight(), actual.height);
- double fps_prop = 0;
- EXPECT_NO_THROW(fps_prop = cap.get(CAP_PROP_FPS));
- if (fps_prop > 0)
- EXPECT_NEAR(fps_prop, bunny_param.getFps(), 1);
- else
- std::cout << "FPS is not available. SKIP check." << std::endl;
- int count_prop = 0;
- EXPECT_NO_THROW(count_prop = (int)cap.get(CAP_PROP_FRAME_COUNT));
- // mpg file reports 5.08 sec * 24 fps => property returns 122 frames
- // but actual number of frames returned is 125
- if (ext != "mpg")
- {
- if (count_prop > 0)
- {
- EXPECT_EQ(bunny_param.getCount(), count_prop);
- }
- }
- int count_actual = 0;
- while (cap.isOpened())
- {
- Mat frame;
- EXPECT_NO_THROW(cap >> frame);
- if (frame.empty())
- break;
- EXPECT_EQ(bunny_param.getWidth(), frame.cols);
- EXPECT_EQ(bunny_param.getHeight(), frame.rows);
- count_actual += 1;
- if (::testing::Test::HasFailure() && count_actual % 10 == 0)
- break;
- }
- if (count_prop > 0)
- {
- EXPECT_NEAR(bunny_param.getCount(), count_actual, 1);
- }
- else
- std::cout << "Frames counter is not available. Actual frames: " << count_actual << ". SKIP check." << std::endl;
- }
- void doTimestampTest()
- {
- if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))
- throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
- // GStreamer: https://github.com/opencv/opencv/issues/19025
- if (apiPref == CAP_GSTREAMER)
- throw SkipTestException(cv::String("Backend ") + cv::videoio_registry::getBackendName(apiPref) +
- cv::String(" does not return reliable values for CAP_PROP_POS_MSEC property"));
- if (((apiPref == CAP_FFMPEG) && ((ext == "h264") || (ext == "h265"))))
- throw SkipTestException(cv::String("Backend ") + cv::videoio_registry::getBackendName(apiPref) +
- cv::String(" does not support CAP_PROP_POS_MSEC option"));
- VideoCapture cap;
- EXPECT_NO_THROW(cap.open(video_file, apiPref));
- if (!cap.isOpened())
- throw SkipTestException(cv::String("Backend ") + cv::videoio_registry::getBackendName(apiPref) +
- cv::String(" can't open the video: ") + video_file);
- Mat img;
- for(int i = 0; i < 10; i++)
- {
- double timestamp = 0;
- ASSERT_NO_THROW(cap >> img);
- EXPECT_NO_THROW(timestamp = cap.get(CAP_PROP_POS_MSEC));
- if (cvtest::debugLevel > 0)
- std::cout << "i = " << i << ": timestamp = " << timestamp << std::endl;
- const double frame_period = 1000.f/bunny_param.getFps();
- // NOTE: eps == frame_period, because videoCapture returns frame begining timestamp or frame end
- // timestamp depending on codec and back-end. So the first frame has timestamp 0 or frame_period.
- EXPECT_NEAR(timestamp, i*frame_period, frame_period) << "i=" << i;
- }
- }
- };
- //==================================================================================================
- struct Ext_Fourcc_PSNR
- {
- const char* ext;
- const char* fourcc;
- float PSNR;
- VideoCaptureAPIs api;
- };
- typedef tuple<Size, Ext_Fourcc_PSNR> Size_Ext_Fourcc_PSNR;
- class videoio_synthetic : public Videoio_Test_Base, public testing::TestWithParam<Size_Ext_Fourcc_PSNR>
- {
- Size frame_size;
- int fourcc;
- float PSNR_GT;
- int frame_count;
- double fps;
- public:
- videoio_synthetic()
- {
- frame_size = get<0>(GetParam());
- const Ext_Fourcc_PSNR p = get<1>(GetParam());
- ext = p.ext;
- fourcc = fourccFromString(p.fourcc);
- PSNR_GT = p.PSNR;
- video_file = cv::tempfile((fourccToString(fourcc) + "." + ext).c_str());
- frame_count = 100;
- fps = 25.;
- apiPref = p.api;
- }
- void TearDown()
- {
- remove(video_file.c_str());
- }
- virtual void writeVideo()
- {
- Mat img(frame_size, CV_8UC3);
- VideoWriter writer;
- EXPECT_NO_THROW(writer.open(video_file, apiPref, fourcc, fps, frame_size, true));
- ASSERT_TRUE(writer.isOpened());
- for(int i = 0; i < frame_count; ++i )
- {
- generateFrame(i, frame_count, img);
- EXPECT_NO_THROW(writer << img);
- if (::testing::Test::HasFailure() && i % 10 == 0)
- break;
- }
- EXPECT_NO_THROW(writer.release());
- }
- virtual void checkFrameContent(Mat & img, int idx)
- {
- Mat imgGT(frame_size, CV_8UC3);
- generateFrame(idx, frame_count, imgGT);
- double psnr = cvtest::PSNR(img, imgGT);
- ASSERT_GT(psnr, PSNR_GT) << "frame " << idx;
- }
- virtual void checkFrameCount(int &actual)
- {
- Range expected_frame_count = Range(frame_count, frame_count);
- // Hack! Newer FFmpeg versions in this combination produce a file
- // whose reported duration is one frame longer than needed, and so
- // the calculated frame count is also off by one. Ideally, we'd want
- // to fix both writing (to produce the correct duration) and reading
- // (to correctly report frame count for such files), but I don't know
- // how to do either, so this is a workaround for now.
- if (fourcc == VideoWriter::fourcc('M', 'P', 'E', 'G') && ext == "mkv")
- expected_frame_count.end += 1;
- // Workaround for some gstreamer pipelines
- if (apiPref == CAP_GSTREAMER)
- expected_frame_count.start -= 1;
- ASSERT_LE(expected_frame_count.start, actual);
- ASSERT_GE(expected_frame_count.end, actual);
- actual = expected_frame_count.start; // adjust actual frame boundary to possible minimum
- }
- };
- //==================================================================================================
- static const VideoCaptureAPIs backend_params[] = {
- #ifdef HAVE_AVFOUNDATION
- CAP_AVFOUNDATION,
- #endif
- #ifdef _WIN32
- CAP_MSMF,
- #endif
- CAP_GSTREAMER,
- CAP_FFMPEG,
- #ifdef HAVE_XINE
- CAP_XINE,
- #endif
- CAP_OPENCV_MJPEG
- // CAP_INTEL_MFX
- };
- static const string bunny_params[] = {
- string("wmv"),
- string("mov"),
- string("mp4"),
- string("mpg"),
- string("avi"),
- string("h264"),
- string("h265"),
- string("mjpg.avi")
- };
- TEST_P(videoio_bunny, read_position) { doTest(); }
- TEST_P(videoio_bunny, frame_count) { doFrameCountTest(); }
- TEST_P(videoio_bunny, frame_timestamp) { doTimestampTest(); }
- INSTANTIATE_TEST_CASE_P(videoio, videoio_bunny,
- testing::Combine(
- testing::ValuesIn(bunny_params),
- testing::ValuesIn(backend_params)));
- inline static std::ostream &operator<<(std::ostream &out, const Ext_Fourcc_PSNR &p)
- {
- out << "FOURCC(" << p.fourcc << "), ." << p.ext << ", " << p.api << ", " << p.PSNR << "dB"; return out;
- }
- static Ext_Fourcc_PSNR synthetic_params[] = {
- #ifdef _WIN32
- #if !defined(_M_ARM)
- {"wmv", "WMV1", 30.f, CAP_MSMF},
- {"wmv", "WMV2", 30.f, CAP_MSMF},
- #endif
- {"wmv", "WMV3", 30.f, CAP_MSMF},
- {"wmv", "WVC1", 30.f, CAP_MSMF},
- {"mov", "H264", 30.f, CAP_MSMF},
- #endif
- #ifdef HAVE_AVFOUNDATION
- {"mov", "H264", 30.f, CAP_AVFOUNDATION},
- {"mov", "MJPG", 30.f, CAP_AVFOUNDATION},
- {"mp4", "H264", 30.f, CAP_AVFOUNDATION},
- {"mp4", "MJPG", 30.f, CAP_AVFOUNDATION},
- {"m4v", "H264", 30.f, CAP_AVFOUNDATION},
- {"m4v", "MJPG", 30.f, CAP_AVFOUNDATION},
- #endif
- {"avi", "XVID", 30.f, CAP_FFMPEG},
- {"avi", "MPEG", 30.f, CAP_FFMPEG},
- {"avi", "IYUV", 30.f, CAP_FFMPEG},
- {"avi", "MJPG", 30.f, CAP_FFMPEG},
- {"mkv", "XVID", 30.f, CAP_FFMPEG},
- {"mkv", "MPEG", 30.f, CAP_FFMPEG},
- {"mkv", "MJPG", 30.f, CAP_FFMPEG},
- {"avi", "MPEG", 28.f, CAP_GSTREAMER},
- {"avi", "MJPG", 30.f, CAP_GSTREAMER},
- {"avi", "H264", 30.f, CAP_GSTREAMER},
- {"mkv", "MPEG", 28.f, CAP_GSTREAMER},
- {"mkv", "MJPG", 30.f, CAP_GSTREAMER},
- {"mkv", "H264", 30.f, CAP_GSTREAMER},
- {"avi", "MJPG", 30.f, CAP_OPENCV_MJPEG},
- };
- Size all_sizes[] = {
- Size(640, 480),
- Size(976, 768)
- };
- TEST_P(videoio_synthetic, write_read_position) { doTest(); }
- INSTANTIATE_TEST_CASE_P(videoio, videoio_synthetic,
- testing::Combine(
- testing::ValuesIn(all_sizes),
- testing::ValuesIn(synthetic_params)));
- struct Ext_Fourcc_API
- {
- const char* ext;
- const char* fourcc;
- VideoCaptureAPIs api;
- };
- inline static std::ostream &operator<<(std::ostream &out, const Ext_Fourcc_API &p)
- {
- out << "(FOURCC(" << p.fourcc << "), \"" << p.ext << "\", " << p.api << ")"; return out;
- }
- class Videoio_Writer : public Videoio_Test_Base, public testing::TestWithParam<Ext_Fourcc_API>
- {
- protected:
- Size frame_size;
- int fourcc;
- double fps;
- public:
- Videoio_Writer()
- {
- frame_size = Size(640, 480);
- const Ext_Fourcc_API p = GetParam();
- ext = p.ext;
- fourcc = fourccFromString(p.fourcc);
- if (ext.size() == 3)
- video_file = cv::tempfile((fourccToString(fourcc) + "." + ext).c_str());
- else
- video_file = ext;
- fps = 25.;
- apiPref = p.api;
- }
- void SetUp()
- {
- }
- void TearDown()
- {
- if (ext.size() == 3)
- (void)remove(video_file.c_str());
- }
- };
- TEST_P(Videoio_Writer, write_nothing)
- {
- if (!cv::videoio_registry::hasBackend(apiPref))
- throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
- VideoWriter writer;
- EXPECT_NO_THROW(writer.open(video_file, apiPref, fourcc, fps, frame_size, true));
- ASSERT_TRUE(writer.isOpened());
- #if 0 // no frames
- cv::Mat m(frame_size, CV_8UC3, Scalar::all(127));
- writer << m;
- #endif
- EXPECT_NO_THROW(writer.release());
- }
- static vector<Ext_Fourcc_API> generate_Ext_Fourcc_API()
- {
- const size_t N = sizeof(synthetic_params)/sizeof(synthetic_params[0]);
- vector<Ext_Fourcc_API> result; result.reserve(N);
- for (size_t i = 0; i < N; i++)
- {
- const Ext_Fourcc_PSNR& src = synthetic_params[i];
- Ext_Fourcc_API e = { src.ext, src.fourcc, src.api };
- result.push_back(e);
- }
- {
- Ext_Fourcc_API e = { "appsrc ! videoconvert ! video/x-raw, format=(string)NV12 ! filesink location=test.nv12", "\0\0\0\0", CAP_GSTREAMER };
- result.push_back(e);
- }
- {
- Ext_Fourcc_API e = { "appsrc ! videoconvert ! video/x-raw, format=(string)I420 ! matroskamux ! filesink location=test.mkv", "\0\0\0\0", CAP_GSTREAMER };
- result.push_back(e);
- }
- return result;
- }
- INSTANTIATE_TEST_CASE_P(videoio, Videoio_Writer, testing::ValuesIn(generate_Ext_Fourcc_API()));
- TEST(Videoio, exceptions)
- {
- VideoCapture cap;
- Mat mat;
- EXPECT_FALSE(cap.grab());
- EXPECT_FALSE(cap.retrieve(mat));
- EXPECT_FALSE(cap.set(CAP_PROP_POS_FRAMES, 1));
- EXPECT_FALSE(cap.open("this_does_not_exist.avi", CAP_OPENCV_MJPEG));
- cap.setExceptionMode(true);
- EXPECT_THROW(cap.grab(), Exception);
- EXPECT_THROW(cap.retrieve(mat), Exception);
- EXPECT_THROW(cap.set(CAP_PROP_POS_FRAMES, 1), Exception);
- EXPECT_THROW(cap.open("this_does_not_exist.avi", CAP_OPENCV_MJPEG), Exception);
- }
- typedef Videoio_Writer Videoio_Writer_bad_fourcc;
- TEST_P(Videoio_Writer_bad_fourcc, nocrash)
- {
- if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))
- throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
- VideoWriter writer;
- EXPECT_NO_THROW(writer.open(video_file, apiPref, fourcc, fps, frame_size, true));
- ASSERT_FALSE(writer.isOpened());
- EXPECT_NO_THROW(writer.release());
- }
- static vector<Ext_Fourcc_API> generate_Ext_Fourcc_API_nocrash()
- {
- static const Ext_Fourcc_API params[] = {
- #ifdef HAVE_MSMF_DISABLED // MSMF opens writer stream
- {"wmv", "aaaa", CAP_MSMF},
- {"mov", "aaaa", CAP_MSMF},
- #endif
- #ifdef HAVE_QUICKTIME
- {"mov", "aaaa", CAP_QT},
- {"avi", "aaaa", CAP_QT},
- {"mkv", "aaaa", CAP_QT},
- #endif
- #ifdef HAVE_AVFOUNDATION
- {"mov", "aaaa", CAP_AVFOUNDATION},
- {"mp4", "aaaa", CAP_AVFOUNDATION},
- {"m4v", "aaaa", CAP_AVFOUNDATION},
- #endif
- #ifdef HAVE_FFMPEG
- {"avi", "aaaa", CAP_FFMPEG},
- {"mkv", "aaaa", CAP_FFMPEG},
- #endif
- #ifdef HAVE_GSTREAMER
- {"avi", "aaaa", CAP_GSTREAMER},
- {"mkv", "aaaa", CAP_GSTREAMER},
- #endif
- {"avi", "aaaa", CAP_OPENCV_MJPEG},
- };
- const size_t N = sizeof(params)/sizeof(params[0]);
- vector<Ext_Fourcc_API> result; result.reserve(N);
- for (size_t i = 0; i < N; i++)
- {
- const Ext_Fourcc_API& src = params[i];
- Ext_Fourcc_API e = { src.ext, src.fourcc, src.api };
- result.push_back(e);
- }
- return result;
- }
- INSTANTIATE_TEST_CASE_P(videoio, Videoio_Writer_bad_fourcc, testing::ValuesIn(generate_Ext_Fourcc_API_nocrash()));
- typedef testing::TestWithParam<VideoCaptureAPIs> safe_capture;
- TEST_P(safe_capture, frames_independency)
- {
- VideoCaptureAPIs apiPref = GetParam();
- if (!videoio_registry::hasBackend(apiPref))
- throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
- VideoCapture cap;
- String video_file = BunnyParameters::getFilename(String(".avi"));
- EXPECT_NO_THROW(cap.open(video_file, apiPref));
- if (!cap.isOpened())
- {
- std::cout << "SKIP test: backend " << apiPref << " can't open the video: " << video_file << std::endl;
- return;
- }
- Mat frames[10];
- Mat hardCopies[10];
- for(int i = 0; i < 10; i++)
- {
- ASSERT_NO_THROW(cap >> frames[i]);
- EXPECT_FALSE(frames[i].empty());
- hardCopies[i] = frames[i].clone();
- }
- for(int i = 0; i < 10; i++)
- EXPECT_EQ(0, cv::norm(frames[i], hardCopies[i], NORM_INF)) << i;
- }
- static VideoCaptureAPIs safe_apis[] = {CAP_FFMPEG, CAP_GSTREAMER, CAP_MSMF,CAP_AVFOUNDATION};
- INSTANTIATE_TEST_CASE_P(videoio, safe_capture, testing::ValuesIn(safe_apis));
- //==================================================================================================
- // TEST_P(videocapture_acceleration, ...)
- struct VideoCaptureAccelerationInput
- {
- const char* filename;
- double psnr_threshold;
- };
- static inline
- std::ostream& operator<<(std::ostream& out, const VideoCaptureAccelerationInput& p)
- {
- out << p.filename;
- return out;
- }
- typedef testing::TestWithParam<tuple<VideoCaptureAccelerationInput, VideoCaptureAPIs, VideoAccelerationType, bool>> videocapture_acceleration;
- TEST_P(videocapture_acceleration, read)
- {
- auto param = GetParam();
- std::string filename = get<0>(param).filename;
- double psnr_threshold = get<0>(param).psnr_threshold;
- VideoCaptureAPIs backend = get<1>(param);
- VideoAccelerationType va_type = get<2>(param);
- bool use_umat = get<3>(param);
- const int frameNum = 15;
- std::string filepath = cvtest::findDataFile("video/" + filename);
- if (backend == CAP_MSMF && (
- filename == "sample_322x242_15frames.yuv420p.mjpeg.mp4" ||
- filename == "sample_322x242_15frames.yuv420p.libx265.mp4" ||
- filename == "sample_322x242_15frames.yuv420p.libaom-av1.mp4" ||
- filename == "sample_322x242_15frames.yuv420p.mpeg2video.mp4"
- ))
- throw SkipTestException("Format/codec is not supported");
- std::string backend_name = cv::videoio_registry::getBackendName(backend);
- if (!videoio_registry::hasBackend(backend))
- throw SkipTestException(cv::String("Backend is not available/disabled: ") + backend_name);
- // HW reader
- std::vector<int> params = { CAP_PROP_HW_ACCELERATION, static_cast<int>(va_type) };
- if (use_umat)
- {
- if (backend != CAP_FFMPEG)
- throw SkipTestException(cv::String("UMat/OpenCL mapping is not supported by current backend: ") + backend_name);
- if (!cv::videoio_registry::isBackendBuiltIn(backend))
- throw SkipTestException(cv::String("UMat/OpenCL mapping is not supported through plugins yet: ") + backend_name);
- params.push_back(CAP_PROP_HW_ACCELERATION_USE_OPENCL);
- params.push_back(1);
- }
- VideoCapture hw_reader(filepath, backend, params);
- if (!hw_reader.isOpened())
- {
- if (use_umat)
- {
- throw SkipTestException(backend_name + " VideoCapture on " + filename + " not supported with HW acceleration + OpenCL/Umat mapping, skipping");
- }
- else if (va_type == VIDEO_ACCELERATION_ANY || va_type == VIDEO_ACCELERATION_NONE)
- {
- // ANY HW acceleration should have fallback to SW codecs
- VideoCapture sw_reader(filepath, backend, {
- CAP_PROP_HW_ACCELERATION, VIDEO_ACCELERATION_NONE
- });
- if (!sw_reader.isOpened())
- throw SkipTestException(backend_name + " VideoCapture on " + filename + " not supported, skipping");
- ASSERT_TRUE(hw_reader.isOpened()) << "ANY HW acceleration should have fallback to SW codecs";
- }
- else
- {
- throw SkipTestException(backend_name + " VideoCapture on " + filename + " not supported with HW acceleration, skipping");
- }
- }
- VideoAccelerationType actual_va = static_cast<VideoAccelerationType>(static_cast<int>(hw_reader.get(CAP_PROP_HW_ACCELERATION)));
- if (va_type != VIDEO_ACCELERATION_ANY && va_type != VIDEO_ACCELERATION_NONE)
- {
- ASSERT_EQ((int)actual_va, (int)va_type) << "actual_va=" << actual_va << ", va_type=" << va_type;
- }
- std::cout << "VideoCapture " << backend_name << ":" << actual_va << std::endl << std::flush;
- double min_psnr_original = 1000;
- for (int i = 0; i < frameNum; i++)
- {
- SCOPED_TRACE(cv::format("frame=%d", i));
- Mat frame;
- if (use_umat)
- {
- UMat umat;
- bool read_umat_result = hw_reader.read(umat);
- if (!read_umat_result && i == 0)
- {
- if (filename == "sample_322x242_15frames.yuv420p.libvpx-vp9.mp4")
- throw SkipTestException("Unable to read the first frame with VP9 codec (media stack misconfiguration / bug)");
- // FFMPEG: [av1 @ 0000027ac07d1340] Your platform doesn't suppport hardware accelerated AV1 decoding.
- if (filename == "sample_322x242_15frames.yuv420p.libaom-av1.mp4")
- throw SkipTestException("Unable to read the first frame with AV1 codec (missing support)");
- }
- EXPECT_TRUE(read_umat_result);
- ASSERT_FALSE(umat.empty());
- umat.copyTo(frame);
- }
- else
- {
- bool read_result = hw_reader.read(frame);
- if (!read_result && i == 0)
- {
- if (filename == "sample_322x242_15frames.yuv420p.libvpx-vp9.mp4")
- throw SkipTestException("Unable to read the first frame with VP9 codec (media stack misconfiguration / bug)");
- // FFMPEG: [av1 @ 0000027ac07d1340] Your platform doesn't suppport hardware accelerated AV1 decoding.
- if (filename == "sample_322x242_15frames.yuv420p.libaom-av1.mp4")
- throw SkipTestException("Unable to read the first frame with AV1 codec (missing support)");
- }
- EXPECT_TRUE(read_result);
- }
- ASSERT_FALSE(frame.empty());
- if (cvtest::debugLevel > 0)
- {
- imwrite(cv::format("test_frame%03d.png", i), frame);
- }
- Mat original(frame.size(), CV_8UC3, Scalar::all(0));
- generateFrame(i, frameNum, original);
- double psnr = cvtest::PSNR(frame, original);
- if (psnr < min_psnr_original)
- min_psnr_original = psnr;
- }
- std::ostringstream ss; ss << actual_va;
- std::string actual_va_str = ss.str();
- std::cout << "VideoCapture with acceleration = " << cv::format("%-6s @ %-10s", actual_va_str.c_str(), backend_name.c_str())
- << " on " << filename
- << " with PSNR-original = " << min_psnr_original
- << std::endl << std::flush;
- EXPECT_GE(min_psnr_original, psnr_threshold);
- }
- static const VideoCaptureAccelerationInput hw_filename[] = {
- { "sample_322x242_15frames.yuv420p.libxvid.mp4", 28.0 },
- { "sample_322x242_15frames.yuv420p.mjpeg.mp4", 20.0 },
- { "sample_322x242_15frames.yuv420p.mpeg2video.mp4", 24.0 }, // GSTREAMER on Ubuntu 18.04
- { "sample_322x242_15frames.yuv420p.libx264.mp4", 24.0 }, // GSTREAMER on Ubuntu 18.04
- { "sample_322x242_15frames.yuv420p.libx265.mp4", 30.0 },
- { "sample_322x242_15frames.yuv420p.libvpx-vp9.mp4", 30.0 },
- { "sample_322x242_15frames.yuv420p.libaom-av1.mp4", 30.0 }
- };
- static const VideoCaptureAPIs hw_backends[] = {
- CAP_FFMPEG,
- CAP_GSTREAMER,
- #ifdef _WIN32
- CAP_MSMF,
- #endif
- };
- static const VideoAccelerationType hw_types[] = {
- VIDEO_ACCELERATION_NONE,
- VIDEO_ACCELERATION_ANY,
- VIDEO_ACCELERATION_MFX,
- #ifdef _WIN32
- VIDEO_ACCELERATION_D3D11,
- #else
- VIDEO_ACCELERATION_VAAPI,
- #endif
- };
- static bool hw_use_umat[] = {
- false,
- true
- };
- INSTANTIATE_TEST_CASE_P(videoio, videocapture_acceleration, testing::Combine(
- testing::ValuesIn(hw_filename),
- testing::ValuesIn(hw_backends),
- testing::ValuesIn(hw_types),
- testing::ValuesIn(hw_use_umat)
- ));
- ////////////////////////////////////////// TEST_P(video_acceleration, write_read)
- typedef tuple<Ext_Fourcc_PSNR, VideoAccelerationType, bool> VATestParams;
- typedef testing::TestWithParam<VATestParams> videowriter_acceleration;
- TEST_P(videowriter_acceleration, write)
- {
- auto param = GetParam();
- VideoCaptureAPIs backend = get<0>(param).api;
- std::string codecid = get<0>(param).fourcc;
- std::string extension = get<0>(param).ext;
- double psnr_threshold = get<0>(param).PSNR;
- VideoAccelerationType va_type = get<1>(param);
- bool use_umat = get<2>(param);
- std::string backend_name = cv::videoio_registry::getBackendName(backend);
- if (!videoio_registry::hasBackend(backend))
- throw SkipTestException(cv::String("Backend is not available/disabled: ") + backend_name);
- const Size sz(640, 480);
- const int frameNum = 15;
- const double fps = 25;
- std::string filename = tempfile("videowriter_acceleration.") + extension;
- // Write video
- VideoAccelerationType actual_va;
- {
- std::vector<int> params = { VIDEOWRITER_PROP_HW_ACCELERATION, static_cast<int>(va_type) };
- if (use_umat) {
- if (backend != CAP_FFMPEG)
- throw SkipTestException(cv::String("UMat/OpenCL mapping is not supported by current backend: ") + backend_name);
- if (!cv::videoio_registry::isBackendBuiltIn(backend))
- throw SkipTestException(cv::String("UMat/OpenCL mapping is not supported through plugins yet: ") + backend_name);
- params.push_back(VIDEOWRITER_PROP_HW_ACCELERATION_USE_OPENCL);
- params.push_back(1);
- }
- VideoWriter hw_writer(
- filename,
- backend,
- VideoWriter::fourcc(codecid[0], codecid[1], codecid[2], codecid[3]),
- fps,
- sz,
- params
- );
- if (!hw_writer.isOpened())
- {
- if (use_umat)
- {
- throw SkipTestException(backend_name + " VideoWriter on " + filename + " not supported with HW acceleration + OpenCL/Umat mapping, skipping");
- }
- else if (va_type == VIDEO_ACCELERATION_ANY || va_type == VIDEO_ACCELERATION_NONE)
- {
- // ANY HW acceleration should have fallback to SW codecs
- {
- VideoWriter sw_writer(
- filename,
- backend,
- VideoWriter::fourcc(codecid[0], codecid[1], codecid[2], codecid[3]),
- fps,
- sz,
- {
- VIDEOWRITER_PROP_HW_ACCELERATION, VIDEO_ACCELERATION_NONE,
- }
- );
- if (!sw_writer.isOpened()) {
- remove(filename.c_str());
- throw SkipTestException(backend_name + " VideoWriter on codec " + codecid + " not supported, skipping");
- }
- }
- remove(filename.c_str());
- ASSERT_TRUE(hw_writer.isOpened()) << "ANY HW acceleration should have fallback to SW codecs";
- } else {
- throw SkipTestException(backend_name + " VideoWriter on " + filename + " not supported with HW acceleration, skipping");
- }
- }
- actual_va = static_cast<VideoAccelerationType>(static_cast<int>(hw_writer.get(VIDEOWRITER_PROP_HW_ACCELERATION)));
- if (va_type != VIDEO_ACCELERATION_ANY && va_type != VIDEO_ACCELERATION_NONE)
- {
- ASSERT_EQ((int)actual_va, (int)va_type) << "actual_va=" << actual_va << ", va_type=" << va_type;
- }
- std::cout << "VideoWriter " << backend_name << ":" << actual_va << std::endl << std::flush;
- Mat frame(sz, CV_8UC3);
- for (int i = 0; i < frameNum; ++i) {
- generateFrame(i, frameNum, frame);
- if (use_umat) {
- UMat umat;
- frame.copyTo(umat);
- hw_writer.write(umat);
- }
- else {
- hw_writer.write(frame);
- }
- }
- }
- std::ifstream ofile(filename, std::ios::binary);
- ofile.seekg(0, std::ios::end);
- int64 fileSize = (int64)ofile.tellg();
- ASSERT_GT(fileSize, 0);
- std::cout << "File size: " << fileSize << std::endl;
- // Read video and check PSNR on every frame
- {
- VideoCapture reader(
- filename,
- CAP_ANY /*backend*/,
- { CAP_PROP_HW_ACCELERATION, VIDEO_ACCELERATION_NONE }
- );
- ASSERT_TRUE(reader.isOpened());
- double min_psnr = 1000;
- Mat reference(sz, CV_8UC3);
- for (int i = 0; i < frameNum; ++i) {
- Mat actual;
- if (use_umat) {
- UMat umat;
- EXPECT_TRUE(reader.read(umat));
- umat.copyTo(actual);
- }
- else {
- EXPECT_TRUE(reader.read(actual));
- }
- EXPECT_FALSE(actual.empty());
- generateFrame(i, frameNum, reference);
- EXPECT_EQ(reference.size(), actual.size());
- EXPECT_EQ(reference.depth(), actual.depth());
- EXPECT_EQ(reference.channels(), actual.channels());
- double psnr = cvtest::PSNR(actual, reference);
- EXPECT_GE(psnr, psnr_threshold) << " frame " << i;
- if (psnr < min_psnr)
- min_psnr = psnr;
- }
- Mat actual;
- EXPECT_FALSE(reader.read(actual));
- {
- std::ostringstream ss; ss << actual_va;
- std::string actual_va_str = ss.str();
- std::cout << "VideoWriter with acceleration = " << cv::format("%-6s @ %-10s", actual_va_str.c_str(), backend_name.c_str())
- << " on codec=" << codecid << " (." << extension << ")"
- << ", bitrate = " << fileSize / (frameNum / fps)
- << ", with PSNR-original = " << min_psnr
- << std::endl << std::flush;
- }
- remove(filename.c_str());
- }
- }
- static Ext_Fourcc_PSNR hw_codecs[] = {
- {"mp4", "MPEG", 29.f, CAP_FFMPEG},
- {"mp4", "H264", 29.f, CAP_FFMPEG},
- {"mp4", "HEVC", 29.f, CAP_FFMPEG},
- {"avi", "MJPG", 29.f, CAP_FFMPEG},
- {"avi", "XVID", 29.f, CAP_FFMPEG},
- //{"webm", "VP8", 29.f, CAP_FFMPEG},
- //{"webm", "VP9", 29.f, CAP_FFMPEG},
- {"mkv", "MPEG", 29.f, CAP_GSTREAMER},
- {"mkv", "H264", 29.f, CAP_GSTREAMER},
- #ifdef _WIN32
- {"mp4", "MPEG", 29.f, CAP_MSMF},
- {"mp4", "H264", 29.f, CAP_MSMF},
- #endif
- };
- INSTANTIATE_TEST_CASE_P(videoio, videowriter_acceleration, testing::Combine(
- testing::ValuesIn(hw_codecs),
- testing::ValuesIn(hw_types),
- testing::ValuesIn(hw_use_umat)
- ));
- } // namespace
|