| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110 |
- // This file is part of OpenCV project.
- // It is subject to the license terms in the LICENSE file found in the top-level directory
- // of this distribution and at http://opencv.org/license.html.
- #include "test_precomp.hpp"
- using namespace std;
- namespace opencv_test { namespace {
- static inline long long getFileSize(const string &filename)
- {
- ifstream f(filename, ios_base::in | ios_base::binary);
- f.seekg(0, ios_base::end);
- return f.tellg();
- }
- typedef tuple<string, string, Size> FourCC_Ext_Size;
- typedef testing::TestWithParam< FourCC_Ext_Size > videoio_ffmpeg;
- TEST_P(videoio_ffmpeg, write_big)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- const string fourcc = get<0>(GetParam());
- const string ext = get<1>(GetParam());
- const Size sz = get<2>(GetParam());
- const double time_sec = 1;
- const double fps = 25;
- ostringstream buf;
- buf << "write_big_" << fourcc << "." << ext;
- const string filename = tempfile(buf.str().c_str());
- VideoWriter writer(filename, CAP_FFMPEG, fourccFromString(fourcc), fps, sz);
- if (ext == "mp4" && fourcc == "H264" && !writer.isOpened())
- {
- throw cvtest::SkipTestException("H264/mp4 codec is not supported - SKIP");
- }
- ASSERT_TRUE(writer.isOpened());
- Mat img(sz, CV_8UC3, Scalar::all(0));
- const int coeff = cvRound(min(sz.width, sz.height)/(fps * time_sec));
- for (int i = 0 ; i < static_cast<int>(fps * time_sec); i++ )
- {
- 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;
- }
- writer.release();
- EXPECT_GT(getFileSize(filename), 8192);
- remove(filename.c_str());
- }
- #if defined(OPENCV_32BIT_CONFIGURATION)
- static const Size bigSize(1920, 1080);
- #else
- static const Size bigSize(4096, 4096);
- #endif
- const FourCC_Ext_Size entries[] =
- {
- make_tuple("", "avi", bigSize),
- make_tuple("DX50", "avi", bigSize),
- make_tuple("FLV1", "avi", bigSize),
- make_tuple("H261", "avi", Size(352, 288)),
- make_tuple("H263", "avi", Size(704, 576)),
- make_tuple("I420", "avi", bigSize),
- make_tuple("MJPG", "avi", bigSize),
- make_tuple("mp4v", "avi", bigSize),
- make_tuple("MPEG", "avi", Size(720, 576)),
- make_tuple("XVID", "avi", bigSize),
- make_tuple("H264", "mp4", Size(4096, 2160)),
- make_tuple("FFV1", "avi", bigSize),
- make_tuple("FFV1", "mkv", bigSize)
- };
- inline static std::string videoio_ffmpeg_name_printer(const testing::TestParamInfo<videoio_ffmpeg::ParamType>& info)
- {
- std::ostringstream os;
- const string & fourcc = get<0>(info.param);
- const Size sz = get<2>(info.param);
- os << (fourcc.size() == 0 ? "NONE" : fourcc) << "_" << get<1>(info.param) << "_" << sz.height << "p";
- return os.str();
- }
- INSTANTIATE_TEST_CASE_P(videoio, videoio_ffmpeg, testing::ValuesIn(entries), videoio_ffmpeg_name_printer);
- //==========================================================================
- TEST(videoio_ffmpeg, image)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- const string filename = findDataFile("readwrite/ordinary.bmp");
- Mat image = imread(filename, IMREAD_COLOR);
- ASSERT_FALSE(image.empty());
- VideoCapture cap(filename, CAP_FFMPEG);
- ASSERT_TRUE(cap.isOpened());
- Mat frame1, frame2;
- cap >> frame1 >> frame2;
- ASSERT_FALSE(frame1.empty());
- ASSERT_TRUE(frame2.empty());
- ASSERT_EQ(0, cvtest::norm(image, frame1, NORM_INF));
- }
- //==========================================================================
- typedef tuple<string, int, bool> videoio_read_params_t;
- typedef testing::TestWithParam< testing::tuple<videoio_read_params_t, int, bool>> videoio_read;
- TEST_P(videoio_read, threads)
- {
- const VideoCaptureAPIs api = CAP_FFMPEG;
- if (!videoio_registry::hasBackend(api))
- throw SkipTestException("Backend was not found");
- const string fileName = get<0>(get<0>(GetParam()));
- const int nFrames = get<1>(get<0>(GetParam()));
- const bool fixedThreadCount = get<2>(get<0>(GetParam()));
- const int nThreads = get<1>(GetParam());
- const bool rawRead = get<2>(GetParam());
- VideoCapture cap(findDataFile(fileName), api, { CAP_PROP_N_THREADS, nThreads });
- if (!cap.isOpened())
- throw SkipTestException("Video stream is not supported");
- if (nThreads == 0 || fixedThreadCount)
- EXPECT_EQ(cap.get(CAP_PROP_N_THREADS), VideoCapture(findDataFile(fileName), api).get(CAP_PROP_N_THREADS));
- else
- EXPECT_EQ(cap.get(CAP_PROP_N_THREADS), nThreads);
- if (rawRead && !cap.set(CAP_PROP_FORMAT, -1)) // turn off video decoder (extract stream)
- throw SkipTestException("Fetching of RAW video streams is not supported");
- Mat frame;
- int n = 0;
- while (cap.read(frame)) {
- ASSERT_FALSE(frame.empty());
- n++;
- }
- ASSERT_EQ(n, nFrames);
- }
- const videoio_read_params_t videoio_read_params[] =
- {
- videoio_read_params_t("video/big_buck_bunny.h264", 125, false),
- //videoio_read_params_t("video/big_buck_bunny.h265", 125, false),
- videoio_read_params_t("video/big_buck_bunny.mjpg.avi", 125, true),
- //videoio_read_params_t("video/big_buck_bunny.mov", 125, false),
- //videoio_read_params_t("video/big_buck_bunny.mp4", 125, false),
- //videoio_read_params_t("video/big_buck_bunny.mpg", 125, false),
- //videoio_read_params_t("video/big_buck_bunny.wmv", 125, true),
- };
- inline static std::string videoio_read_name_printer(const testing::TestParamInfo<videoio_read::ParamType>& info)
- {
- std::ostringstream out;
- out << getExtensionSafe(get<0>(get<0>(info.param))) << "_"
- << get<1>(info.param) << "_"
- << (get<2>(info.param) ? "RAW" : "ENC");
- return out.str();
- }
- INSTANTIATE_TEST_CASE_P(/**/, videoio_read, testing::Combine(testing::ValuesIn(videoio_read_params),
- testing::Values(0, 1, 2, 50),
- testing::Values(true, false)),
- videoio_read_name_printer);
- //==========================================================================
- typedef tuple<VideoCaptureAPIs, string, string, string, string, string> videoio_container_params_t;
- typedef testing::TestWithParam< videoio_container_params_t > videoio_container;
- TEST_P(videoio_container, read)
- {
- const VideoCaptureAPIs api = get<0>(GetParam());
- if (!videoio_registry::hasBackend(api))
- throw SkipTestException("Backend was not found");
- const string path = get<1>(GetParam());
- const string ext = get<2>(GetParam());
- const string ext_raw = get<3>(GetParam());
- const string codec = get<4>(GetParam());
- const string pixelFormat = get<5>(GetParam());
- const string fileName = path + "." + ext;
- const string fileNameOut = tempfile(cv::format("test_container_stream.%s", ext_raw.c_str()).c_str());
- // Write encoded video read using VideoContainer to tmp file
- size_t totalBytes = 0;
- {
- VideoCapture container(findDataFile(fileName), api);
- if (!container.isOpened())
- throw SkipTestException("Video stream is not supported");
- if (!container.set(CAP_PROP_FORMAT, -1)) // turn off video decoder (extract stream)
- throw SkipTestException("Fetching of RAW video streams is not supported");
- ASSERT_EQ(-1.f, container.get(CAP_PROP_FORMAT)); // check
- EXPECT_EQ(codec, fourccToString((int)container.get(CAP_PROP_FOURCC)));
- EXPECT_EQ(pixelFormat, fourccToString((int)container.get(CAP_PROP_CODEC_PIXEL_FORMAT)));
- std::ofstream file(fileNameOut.c_str(), ios::out | ios::trunc | std::ios::binary);
- Mat raw_data;
- while (true)
- {
- container >> raw_data;
- size_t size = raw_data.total();
- if (raw_data.empty())
- break;
- ASSERT_EQ(CV_8UC1, raw_data.type());
- ASSERT_LE(raw_data.dims, 2);
- ASSERT_EQ(raw_data.rows, 1);
- ASSERT_EQ((size_t)raw_data.cols, raw_data.total());
- ASSERT_TRUE(raw_data.isContinuous());
- totalBytes += size;
- file.write(reinterpret_cast<char*>(raw_data.data), size);
- ASSERT_FALSE(file.fail());
- }
- ASSERT_GE(totalBytes, (size_t)39775) << "Encoded stream is too small";
- }
- std::cout << "Checking extracted video stream: " << fileNameOut << " (size: " << totalBytes << " bytes)" << std::endl;
- // Check decoded frames read from original media are equal to frames decoded from tmp file
- {
- VideoCapture capReference(findDataFile(fileName), api);
- ASSERT_TRUE(capReference.isOpened());
- VideoCapture capActual(fileNameOut.c_str(), api);
- ASSERT_TRUE(capActual.isOpened());
- Mat reference, actual;
- int nframes = 0, n_err = 0;
- while (capReference.read(reference) && n_err < 3)
- {
- nframes++;
- ASSERT_TRUE(capActual.read(actual)) << nframes;
- EXPECT_EQ(0, cvtest::norm(actual, reference, NORM_INF)) << "frame=" << nframes << " err=" << ++n_err;
- }
- ASSERT_GT(nframes, 0);
- }
- ASSERT_EQ(0, remove(fileNameOut.c_str()));
- }
- const videoio_container_params_t videoio_container_params[] =
- {
- videoio_container_params_t(CAP_FFMPEG, "video/big_buck_bunny", "h264", "h264", "h264", "I420"),
- videoio_container_params_t(CAP_FFMPEG, "video/big_buck_bunny", "h265", "h265", "hevc", "I420"),
- videoio_container_params_t(CAP_FFMPEG, "video/big_buck_bunny", "mjpg.avi", "mjpg", "MJPG", "I420"),
- videoio_container_params_t(CAP_FFMPEG, "video/sample_322x242_15frames.yuv420p.libx264", "mp4", "h264", "h264", "I420")
- //videoio_container_params_t(CAP_FFMPEG, "video/big_buck_bunny", "h264.mkv", "mkv.h264", "h264", "I420"),
- //videoio_container_params_t(CAP_FFMPEG, "video/big_buck_bunny", "h265.mkv", "mkv.h265", "hevc", "I420"),
- //videoio_container_params_t(CAP_FFMPEG, "video/big_buck_bunny", "h264.mp4", "mp4.avc1", "avc1", "I420"),
- //videoio_container_params_t(CAP_FFMPEG, "video/big_buck_bunny", "h265.mp4", "mp4.hev1", "hev1", "I420"),
- };
- INSTANTIATE_TEST_CASE_P(/**/, videoio_container, testing::ValuesIn(videoio_container_params));
- typedef tuple<VideoCaptureAPIs, string, int, int, int, int, int> videoio_container_get_params_t;
- typedef testing::TestWithParam<videoio_container_get_params_t > videoio_container_get;
- TEST_P(videoio_container_get, read)
- {
- const VideoCaptureAPIs api = get<0>(GetParam());
- if (!videoio_registry::hasBackend(api))
- throw SkipTestException("Backend was not found");
- const string fileName = get<1>(GetParam());
- const int height = get<2>(GetParam());
- const int width = get<3>(GetParam());
- const int nFrames = get<4>(GetParam());
- const int bitrate = get<5>(GetParam());
- const int fps = get<6>(GetParam());
- VideoCapture container(findDataFile(fileName), api, { CAP_PROP_FORMAT, -1 });
- if (!container.isOpened())
- throw SkipTestException("Video stream is not supported");
- const int heightProp = static_cast<int>(container.get(CAP_PROP_FRAME_HEIGHT));
- ASSERT_EQ(height, heightProp);
- const int widthProp = static_cast<int>(container.get(CAP_PROP_FRAME_WIDTH));
- ASSERT_EQ(width, widthProp);
- const int nFramesProp = static_cast<int>(container.get(CAP_PROP_FRAME_COUNT));
- ASSERT_EQ(nFrames, nFramesProp);
- const int bitrateProp = static_cast<int>(container.get(CAP_PROP_BITRATE));
- ASSERT_EQ(bitrate, bitrateProp);
- const double fpsProp = container.get(CAP_PROP_FPS);
- ASSERT_EQ(fps, fpsProp);
- vector<int> displayTimeMs;
- int iFrame = 1;
- while (container.grab()) {
- displayTimeMs.push_back(static_cast<int>(container.get(CAP_PROP_POS_MSEC)));
- const int iFrameProp = static_cast<int>(container.get(CAP_PROP_POS_FRAMES));
- ASSERT_EQ(iFrame++, iFrameProp);
- }
- sort(displayTimeMs.begin(), displayTimeMs.end());
- vector<int> displayTimeDiffMs(displayTimeMs.size());
- std::adjacent_difference(displayTimeMs.begin(), displayTimeMs.end(), displayTimeDiffMs.begin());
- auto minTimeMsIt = min_element(displayTimeDiffMs.begin() + 1, displayTimeDiffMs.end());
- auto maxTimeMsIt = max_element(displayTimeDiffMs.begin() + 1, displayTimeDiffMs.end());
- const int frameTimeMs = static_cast<int>(1000.0 / fps);
- ASSERT_NEAR(frameTimeMs, *minTimeMsIt, 1);
- ASSERT_NEAR(frameTimeMs, *maxTimeMsIt, 1);
- }
- const videoio_container_get_params_t videoio_container_get_params[] =
- {
- videoio_container_get_params_t(CAP_FFMPEG, "video/big_buck_bunny.mp4", 384, 672, 125, 483, 24),
- videoio_container_get_params_t(CAP_FFMPEG, "video/big_buck_bunny.mjpg.avi", 384, 672, 125, 2713, 24),
- videoio_container_get_params_t(CAP_FFMPEG, "video/sample_322x242_15frames.yuv420p.libx264.mp4", 242, 322, 15, 542, 25)
- };
- INSTANTIATE_TEST_CASE_P(/**/, videoio_container_get, testing::ValuesIn(videoio_container_get_params));
- typedef tuple<string, string, int, int, bool, bool> videoio_encapsulate_params_t;
- typedef testing::TestWithParam< videoio_encapsulate_params_t > videoio_encapsulate;
- TEST_P(videoio_encapsulate, write)
- {
- const VideoCaptureAPIs api = CAP_FFMPEG;
- if (!videoio_registry::hasBackend(api))
- throw SkipTestException("FFmpeg backend was not found");
- const string fileName = findDataFile(get<0>(GetParam()));
- const string ext = get<1>(GetParam());
- const int idrPeriod = get<2>(GetParam());
- const int nFrames = get<3>(GetParam());
- const string fileNameOut = tempfile(cv::format("test_encapsulated_stream.%s", ext.c_str()).c_str());
- const bool setPts = get<4>(GetParam());
- const bool tsWorking = get<5>(GetParam());
- // Use VideoWriter to encapsulate encoded video read with VideoReader
- {
- VideoCapture capRaw(fileName, api, { CAP_PROP_FORMAT, -1 });
- ASSERT_TRUE(capRaw.isOpened());
- const int width = static_cast<int>(capRaw.get(CAP_PROP_FRAME_WIDTH));
- const int height = static_cast<int>(capRaw.get(CAP_PROP_FRAME_HEIGHT));
- const double fps = capRaw.get(CAP_PROP_FPS);
- const int codecExtradataIndex = static_cast<int>(capRaw.get(CAP_PROP_CODEC_EXTRADATA_INDEX));
- Mat extraData;
- capRaw.retrieve(extraData, codecExtradataIndex);
- const int fourcc = static_cast<int>(capRaw.get(CAP_PROP_FOURCC));
- const bool mpeg4 = (fourcc == fourccFromString("FMP4"));
- VideoWriter container(fileNameOut, api, fourcc, fps, { width, height }, { VideoWriterProperties::VIDEOWRITER_PROP_RAW_VIDEO, 1, VideoWriterProperties::VIDEOWRITER_PROP_KEY_INTERVAL, idrPeriod });
- ASSERT_TRUE(container.isOpened());
- Mat rawFrame;
- for (int i = 0; i < nFrames; i++) {
- ASSERT_TRUE(capRaw.read(rawFrame));
- if (setPts && i == 0) {
- double dts = capRaw.get(CAP_PROP_DTS_DELAY);
- ASSERT_TRUE(container.set(VIDEOWRITER_PROP_DTS_DELAY, dts)) << "dts=" << dts;
- }
- ASSERT_FALSE(rawFrame.empty());
- if (i == 0 && mpeg4) {
- Mat tmp = rawFrame.clone();
- const size_t newSzt = tmp.total() + extraData.total();
- const int newSz = static_cast<int>(newSzt);
- ASSERT_TRUE(newSzt == static_cast<size_t>(newSz));
- rawFrame = Mat(1, newSz, CV_8UC1);
- memcpy(rawFrame.data, extraData.data, extraData.total());
- memcpy(rawFrame.data + extraData.total(), tmp.data, tmp.total());
- }
- if (setPts) {
- double pts = capRaw.get(CAP_PROP_PTS);
- ASSERT_TRUE(container.set(VIDEOWRITER_PROP_PTS, pts)) << "pts=" << pts;
- }
- container.write(rawFrame);
- }
- container.release();
- }
- std::cout << "Checking encapsulated video container: " << fileNameOut << std::endl;
- // Check encapsulated video container is "identical" to the original
- {
- VideoCapture capReference(fileName), capActual(fileNameOut), capActualRaw(fileNameOut, api, { CAP_PROP_FORMAT, -1 });
- ASSERT_TRUE(capReference.isOpened());
- ASSERT_TRUE(capActual.isOpened());
- ASSERT_TRUE(capActualRaw.isOpened());
- const double fpsReference = capReference.get(CAP_PROP_FPS);
- const double fpsActual = capActual.get(CAP_PROP_FPS);
- ASSERT_NEAR(fpsReference, fpsActual, 1e-2);
- const int nFramesActual = static_cast<int>(capActual.get(CAP_PROP_FRAME_COUNT));
- ASSERT_EQ(nFrames, nFramesActual);
- Mat reference, actual;
- for (int i = 0; i < nFrames; i++) {
- ASSERT_TRUE(capReference.read(reference));
- ASSERT_FALSE(reference.empty());
- ASSERT_TRUE(capActual.read(actual));
- ASSERT_FALSE(actual.empty());
- ASSERT_EQ(0, cvtest::norm(reference, actual, NORM_INF));
- ASSERT_TRUE(capActualRaw.grab());
- const bool keyFrameActual = capActualRaw.get(CAP_PROP_LRF_HAS_KEY_FRAME) == 1.;
- const bool keyFrameReference = idrPeriod ? i % idrPeriod == 0 : 1;
- ASSERT_EQ(keyFrameReference, keyFrameActual);
- if (tsWorking) {
- ASSERT_EQ(round(capReference.get(CAP_PROP_POS_MSEC)), round(capActual.get(CAP_PROP_POS_MSEC)));
- }
- }
- }
- ASSERT_EQ(0, remove(fileNameOut.c_str()));
- }
- const videoio_encapsulate_params_t videoio_encapsulate_params[] =
- {
- videoio_encapsulate_params_t("video/big_buck_bunny.h264", "avi", 125, 125, false, false), // tsWorking = false: no timestamp information
- videoio_encapsulate_params_t("video/big_buck_bunny.h265", "mp4", 125, 125, false, false), // tsWorking = false: no timestamp information
- videoio_encapsulate_params_t("video/big_buck_bunny.wmv", "wmv", 12, 13, false, true),
- videoio_encapsulate_params_t("video/big_buck_bunny.mp4", "mp4", 12, 13, false, true),
- videoio_encapsulate_params_t("video/big_buck_bunny.mjpg.avi", "mp4", 0, 4, false, true),
- videoio_encapsulate_params_t("video/big_buck_bunny.mov", "mp4", 12, 13, false, true),
- videoio_encapsulate_params_t("video/big_buck_bunny.avi", "mp4", 125, 125, false, false), // tsWorking = false: PTS not available for all frames
- videoio_encapsulate_params_t("video/big_buck_bunny.mpg", "mp4", 12, 13, true, true),
- videoio_encapsulate_params_t("video/VID00003-20100701-2204.wmv", "wmv", 12, 13, false, true),
- videoio_encapsulate_params_t("video/VID00003-20100701-2204.mpg", "mp4", 12, 13, false, false), // tsWorking = false: PTS not available for all frames
- videoio_encapsulate_params_t("video/VID00003-20100701-2204.avi", "mp4", 12, 13, false, false), // tsWorking = false: Unable to correctly set PTS when writing
- videoio_encapsulate_params_t("video/VID00003-20100701-2204.3GP", "mp4", 51, 52, false, false), // tsWorking = false: Source with variable fps
- videoio_encapsulate_params_t("video/sample_sorenson.avi", "mp4", 12, 13, false, true),
- videoio_encapsulate_params_t("video/sample_322x242_15frames.yuv420p.libxvid.mp4", "mp4", 3, 4, false, true),
- videoio_encapsulate_params_t("video/sample_322x242_15frames.yuv420p.mpeg2video.mp4", "mpg", 12, 13, false, true),
- videoio_encapsulate_params_t("video/sample_322x242_15frames.yuv420p.mjpeg.mp4", "mp4", 0, 5, false, true),
- videoio_encapsulate_params_t("video/sample_322x242_15frames.yuv420p.libx264.mp4", "ts", 15, 15, true, true),
- videoio_encapsulate_params_t("../cv/tracking/faceocc2/data/faceocc2.webm", "webm", 128, 129, false, true),
- videoio_encapsulate_params_t("../cv/video/1920x1080.avi", "mp4", 12, 13, false, true),
- videoio_encapsulate_params_t("../cv/video/768x576.avi", "avi", 15, 16, false, true),
- // Not supported by with FFmpeg:
- //videoio_encapsulate_params_t("video/sample_322x242_15frames.yuv420p.libx265.mp4", "mp4", 15, 15, true, true),
- //videoio_encapsulate_params_t("video/sample_322x242_15frames.yuv420p.libvpx-vp9.mp4", "mp4", 15, 15, false, true),
- };
- INSTANTIATE_TEST_CASE_P(/**/, videoio_encapsulate, testing::ValuesIn(videoio_encapsulate_params));
- TEST(videoio_encapsulate_set_idr, write)
- {
- const VideoCaptureAPIs api = CAP_FFMPEG;
- if (!videoio_registry::hasBackend(api))
- throw SkipTestException("FFmpeg backend was not found");
- const string fileName = findDataFile("video/big_buck_bunny.mp4");
- const string ext = "mp4";
- const string fileNameOut = tempfile(cv::format("test_encapsulated_stream_set_idr.%s", ext.c_str()).c_str());
- // Use VideoWriter to encapsulate encoded video read with VideoReader
- {
- VideoCapture capRaw(fileName, api, { CAP_PROP_FORMAT, -1 });
- ASSERT_TRUE(capRaw.isOpened());
- const int width = static_cast<int>(capRaw.get(CAP_PROP_FRAME_WIDTH));
- const int height = static_cast<int>(capRaw.get(CAP_PROP_FRAME_HEIGHT));
- const double fps = capRaw.get(CAP_PROP_FPS);
- const int codecExtradataIndex = static_cast<int>(capRaw.get(CAP_PROP_CODEC_EXTRADATA_INDEX));
- Mat extraData;
- capRaw.retrieve(extraData, codecExtradataIndex);
- const int fourcc = static_cast<int>(capRaw.get(CAP_PROP_FOURCC));
- const bool mpeg4 = (fourcc == fourccFromString("FMP4"));
- VideoWriter container(fileNameOut, api, fourcc, fps, { width, height }, { VideoWriterProperties::VIDEOWRITER_PROP_RAW_VIDEO, 1 });
- ASSERT_TRUE(container.isOpened());
- Mat rawFrame;
- int i = 0;
- while (capRaw.read(rawFrame)) {
- ASSERT_FALSE(rawFrame.empty());
- if (i == 0 && mpeg4) {
- Mat tmp = rawFrame.clone();
- const size_t newSzt = tmp.total() + extraData.total();
- const int newSz = static_cast<int>(newSzt);
- ASSERT_TRUE(newSzt == static_cast<size_t>(newSz));
- rawFrame = Mat(1, newSz, CV_8UC1);
- memcpy(rawFrame.data, extraData.data, extraData.total());
- memcpy(rawFrame.data + extraData.total(), tmp.data, tmp.total());
- }
- if (capRaw.get(CAP_PROP_LRF_HAS_KEY_FRAME) != 0)
- container.set(VideoWriterProperties::VIDEOWRITER_PROP_KEY_FLAG, 1);
- else
- container.set(VideoWriterProperties::VIDEOWRITER_PROP_KEY_FLAG, 0);
- container.write(rawFrame);
- i++;
- }
- container.release();
- }
- std::cout << "Checking encapsulated video container: " << fileNameOut << std::endl;
- // Check encapsulated video container is "identical" to the original
- {
- VideoCapture capReference(fileName), capReferenceRaw(fileName, api, { CAP_PROP_FORMAT, -1 }), capActual(fileNameOut), capActualRaw(fileNameOut, api, { CAP_PROP_FORMAT, -1 });
- ASSERT_TRUE(capReference.isOpened());
- ASSERT_TRUE(capActual.isOpened());
- ASSERT_TRUE(capReferenceRaw.isOpened());
- ASSERT_TRUE(capActualRaw.isOpened());
- const double fpsReference = capReference.get(CAP_PROP_FPS);
- const double fpsActual = capActual.get(CAP_PROP_FPS);
- ASSERT_EQ(fpsReference, fpsActual);
- const int nFramesReference = static_cast<int>(capReference.get(CAP_PROP_FRAME_COUNT));
- const int nFramesActual = static_cast<int>(capActual.get(CAP_PROP_FRAME_COUNT));
- ASSERT_EQ(nFramesReference, nFramesActual);
- Mat reference, actual;
- for (int i = 0; i < nFramesReference; i++) {
- ASSERT_TRUE(capReference.read(reference));
- ASSERT_FALSE(reference.empty());
- ASSERT_TRUE(capActual.read(actual));
- ASSERT_FALSE(actual.empty());
- ASSERT_EQ(0, cvtest::norm(reference, actual, NORM_INF));
- ASSERT_TRUE(capReferenceRaw.grab());
- ASSERT_TRUE(capActualRaw.grab());
- const bool keyFrameReference = capActualRaw.get(CAP_PROP_LRF_HAS_KEY_FRAME) == 1.;
- const bool keyFrameActual = capActualRaw.get(CAP_PROP_LRF_HAS_KEY_FRAME) == 1.;
- ASSERT_EQ(keyFrameReference, keyFrameActual);
- }
- }
- ASSERT_EQ(0, remove(fileNameOut.c_str()));
- }
- typedef tuple<string, string, int> videoio_skip_params_t;
- typedef testing::TestWithParam< videoio_skip_params_t > videoio_skip;
- TEST_P(videoio_skip, DISABLED_read) // optional test, may fail in some configurations
- {
- #if CV_VERSION_MAJOR >= 4
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("Backend was not found");
- #endif
- const string path = get<0>(GetParam());
- const string env = get<1>(GetParam());
- const int expectedFrameNumber = get<2>(GetParam());
- #ifdef _WIN32
- _putenv_s("OPENCV_FFMPEG_CAPTURE_OPTIONS", env.c_str());
- #else
- setenv("OPENCV_FFMPEG_CAPTURE_OPTIONS", env.c_str(), 1);
- #endif
- VideoCapture container(findDataFile(path), CAP_FFMPEG);
- #ifdef _WIN32
- _putenv_s("OPENCV_FFMPEG_CAPTURE_OPTIONS", "");
- #else
- setenv("OPENCV_FFMPEG_CAPTURE_OPTIONS", "", 1);
- #endif
- ASSERT_TRUE(container.isOpened());
- Mat reference;
- int nframes = 0, n_err = 0;
- while (container.isOpened())
- {
- if (container.read(reference))
- nframes++;
- else if (++n_err > 3)
- break;
- }
- EXPECT_EQ(expectedFrameNumber, nframes);
- }
- const videoio_skip_params_t videoio_skip_params[] =
- {
- videoio_skip_params_t("video/big_buck_bunny.mp4", "", 125),
- videoio_skip_params_t("video/big_buck_bunny.mp4", "avdiscard;nonkey", 11)
- };
- INSTANTIATE_TEST_CASE_P(/**/, videoio_skip, testing::ValuesIn(videoio_skip_params));
- //==========================================================================
- static void generateFrame(Mat &frame, unsigned int i, const Point ¢er, const Scalar &color)
- {
- frame = Scalar::all(i % 255);
- stringstream buf(ios::out);
- buf << "frame #" << i;
- putText(frame, buf.str(), Point(50, center.y), FONT_HERSHEY_SIMPLEX, 5.0, color, 5, LINE_AA);
- circle(frame, center, i + 2, color, 2, LINE_AA);
- }
- TEST(videoio_ffmpeg, parallel)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- const int NUM = 4;
- const int GRAN = 4;
- const Range R(0, NUM);
- const Size sz(1020, 900);
- const int frameNum = 300;
- const Scalar color(Scalar::all(0));
- const Point center(sz.height / 2, sz.width / 2);
- // Generate filenames
- vector<string> files;
- for (int i = 0; i < NUM; ++i)
- {
- ostringstream stream;
- stream << i << ".avi";
- files.push_back(tempfile(stream.str().c_str()));
- }
- // Write videos
- {
- vector< Ptr<VideoWriter> > writers(NUM);
- auto makeWriters = [&](const Range &r)
- {
- for (int i = r.start; i != r.end; ++i)
- writers[i] = makePtr<VideoWriter>(files[i],
- CAP_FFMPEG,
- VideoWriter::fourcc('X','V','I','D'),
- 25.0f,
- sz);
- };
- parallel_for_(R, makeWriters, GRAN);
- for(int i = 0; i < NUM; ++i)
- {
- ASSERT_TRUE(writers[i]);
- ASSERT_TRUE(writers[i]->isOpened());
- }
- auto writeFrames = [&](const Range &r)
- {
- for (int j = r.start; j < r.end; ++j)
- {
- Mat frame(sz, CV_8UC3);
- for (int i = 0; i < frameNum; ++i)
- {
- generateFrame(frame, i, center, color);
- writers[j]->write(frame);
- }
- }
- };
- parallel_for_(R, writeFrames, GRAN);
- }
- // Read videos
- {
- vector< Ptr<VideoCapture> > readers(NUM);
- auto makeCaptures = [&](const Range &r)
- {
- for (int i = r.start; i != r.end; ++i)
- readers[i] = makePtr<VideoCapture>(files[i], CAP_FFMPEG);
- };
- parallel_for_(R, makeCaptures, GRAN);
- for(int i = 0; i < NUM; ++i)
- {
- ASSERT_TRUE(readers[i]);
- ASSERT_TRUE(readers[i]->isOpened());
- }
- auto readFrames = [&](const Range &r)
- {
- for (int j = r.start; j < r.end; ++j)
- {
- Mat reference(sz, CV_8UC3);
- for (int i = 0; i < frameNum; ++i)
- {
- Mat actual;
- EXPECT_TRUE(readers[j]->read(actual));
- EXPECT_FALSE(actual.empty());
- generateFrame(reference, i, center, color);
- EXPECT_EQ(reference.size(), actual.size());
- EXPECT_EQ(reference.depth(), actual.depth());
- EXPECT_EQ(reference.channels(), actual.channels());
- EXPECT_GE(cvtest::PSNR(actual, reference), 35.0) << "cap" << j << ", frame " << i;
- }
- }
- };
- parallel_for_(R, readFrames, GRAN);
- }
- // Remove files
- for(int i = 0; i < NUM; ++i)
- {
- remove(files[i].c_str());
- }
- }
- typedef std::pair<VideoCaptureProperties, double> cap_property_t;
- typedef std::vector<cap_property_t> cap_properties_t;
- typedef std::pair<std::string, cap_properties_t> ffmpeg_cap_properties_param_t;
- typedef testing::TestWithParam<ffmpeg_cap_properties_param_t> ffmpeg_cap_properties;
- TEST_P(ffmpeg_cap_properties, can_read_property)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- ffmpeg_cap_properties_param_t parameters = GetParam();
- const std::string path = parameters.first;
- const cap_properties_t properties = parameters.second;
- VideoCapture cap(findDataFile(path), CAP_FFMPEG);
- ASSERT_TRUE(cap.isOpened()) << "Can not open " << findDataFile(path);
- for (std::size_t i = 0; i < properties.size(); ++i)
- {
- const cap_property_t& prop = properties[i];
- const double actualValue = cap.get(static_cast<int>(prop.first));
- EXPECT_DOUBLE_EQ(actualValue, prop.second)
- << "Property " << static_cast<int>(prop.first) << " has wrong value";
- }
- }
- cap_properties_t loadBigBuckBunnyFFProbeResults() {
- cap_property_t properties[] = { cap_property_t(CAP_PROP_BITRATE, 5851.),
- cap_property_t(CAP_PROP_FPS, 24.),
- cap_property_t(CAP_PROP_FRAME_HEIGHT, 384.),
- cap_property_t(CAP_PROP_FRAME_WIDTH, 672.) };
- return cap_properties_t(properties, properties + sizeof(properties) / sizeof(cap_property_t));
- }
- const ffmpeg_cap_properties_param_t videoio_ffmpeg_properties[] = {
- ffmpeg_cap_properties_param_t("video/big_buck_bunny.avi", loadBigBuckBunnyFFProbeResults())
- };
- INSTANTIATE_TEST_CASE_P(videoio, ffmpeg_cap_properties, testing::ValuesIn(videoio_ffmpeg_properties));
- typedef tuple<string, string> ffmpeg_get_fourcc_param_t;
- typedef testing::TestWithParam<ffmpeg_get_fourcc_param_t> ffmpeg_get_fourcc;
- TEST_P(ffmpeg_get_fourcc, check_short_codecs)
- {
- const VideoCaptureAPIs api = CAP_FFMPEG;
- if (!videoio_registry::hasBackend(api))
- throw SkipTestException("Backend was not found");
- const string fileName = get<0>(GetParam());
- const string fourcc_string = get<1>(GetParam());
- VideoCapture cap(findDataFile(fileName), api);
- if (!cap.isOpened())
- throw SkipTestException("Video stream is not supported");
- const double fourcc = cap.get(CAP_PROP_FOURCC);
- ASSERT_EQ(fourcc_string, fourccToString((int)fourcc));
- }
- const ffmpeg_get_fourcc_param_t ffmpeg_get_fourcc_param[] =
- {
- ffmpeg_get_fourcc_param_t("../cv/tracking/faceocc2/data/faceocc2.webm", "VP80"),
- ffmpeg_get_fourcc_param_t("video/big_buck_bunny.h265", "hevc"),
- ffmpeg_get_fourcc_param_t("video/big_buck_bunny.h264", "h264"),
- ffmpeg_get_fourcc_param_t("video/sample_322x242_15frames.yuv420p.libvpx-vp9.mp4", "VP90"),
- ffmpeg_get_fourcc_param_t("video/sample_322x242_15frames.yuv420p.libaom-av1.mp4", "AV01"),
- ffmpeg_get_fourcc_param_t("video/big_buck_bunny.mp4", "FMP4"),
- ffmpeg_get_fourcc_param_t("video/sample_322x242_15frames.yuv420p.mpeg2video.mp4", "mpg2"),
- ffmpeg_get_fourcc_param_t("video/sample_322x242_15frames.yuv420p.mjpeg.mp4", "MJPG"),
- ffmpeg_get_fourcc_param_t("video/sample_322x242_15frames.yuv420p.libxvid.mp4", "FMP4"),
- ffmpeg_get_fourcc_param_t("video/sample_322x242_15frames.yuv420p.libx265.mp4", "hevc"),
- ffmpeg_get_fourcc_param_t("video/sample_322x242_15frames.yuv420p.libx264.mp4", "h264")
- };
- inline static std::string ffmpeg_get_fourcc_name_printer(const testing::TestParamInfo<ffmpeg_get_fourcc::ParamType>& info)
- {
- std::ostringstream os;
- const string & fourcc = get<1>(info.param);
- os << info.index << "_" << (fourcc.size() == 0 ? "NONE" : fourcc);
- return os.str();
- }
- INSTANTIATE_TEST_CASE_P(videoio, ffmpeg_get_fourcc, testing::ValuesIn(ffmpeg_get_fourcc_param), ffmpeg_get_fourcc_name_printer);
- static void ffmpeg_check_read_raw(VideoCapture& cap)
- {
- ASSERT_TRUE(cap.isOpened()) << "Can't open the video";
- Mat data;
- cap >> data;
- EXPECT_EQ(CV_8UC1, data.type()) << "CV_8UC1 != " << typeToString(data.type());
- EXPECT_TRUE(data.rows == 1 || data.cols == 1) << data.size;
- EXPECT_EQ((size_t)29729, data.total());
- cap >> data;
- EXPECT_EQ(CV_8UC1, data.type()) << "CV_8UC1 != " << typeToString(data.type());
- EXPECT_TRUE(data.rows == 1 || data.cols == 1) << data.size;
- EXPECT_EQ((size_t)37118, data.total());
- // 12 is the nearset key frame to frame 18
- EXPECT_TRUE(cap.set(CAP_PROP_POS_FRAMES, 18.));
- EXPECT_EQ(cap.get(CAP_PROP_POS_FRAMES), 12.);
- cap >> data;
- EXPECT_EQ(CV_8UC1, data.type()) << "CV_8UC1 != " << typeToString(data.type());
- EXPECT_TRUE(data.rows == 1 || data.cols == 1) << data.size;
- EXPECT_EQ((size_t)8726, data.total());
- }
- TEST(videoio_ffmpeg, ffmpeg_check_extra_data)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- string video_file = findDataFile("video/big_buck_bunny.mp4");
- VideoCapture cap;
- EXPECT_NO_THROW(cap.open(video_file, CAP_FFMPEG));
- ASSERT_TRUE(cap.isOpened()) << "Can't open the video";
- const int codecExtradataIdx = (int)cap.get(CAP_PROP_CODEC_EXTRADATA_INDEX);
- Mat data;
- ASSERT_TRUE(cap.retrieve(data, codecExtradataIdx));
- EXPECT_EQ(CV_8UC1, data.type()) << "CV_8UC1 != " << typeToString(data.type());
- EXPECT_TRUE(data.rows == 1 || data.cols == 1) << data.size;
- EXPECT_EQ((size_t)45, data.total());
- }
- TEST(videoio_ffmpeg, open_with_property)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- string video_file = findDataFile("video/big_buck_bunny.mp4");
- VideoCapture cap;
- EXPECT_NO_THROW(cap.open(video_file, CAP_FFMPEG, {
- CAP_PROP_FORMAT, -1 // demux only
- }));
- // confirm properties are returned without initializing AVCodecContext
- EXPECT_EQ(cap.get(CAP_PROP_FORMAT), -1);
- EXPECT_EQ(static_cast<int>(cap.get(CAP_PROP_FOURCC)), fourccFromString("FMP4"));
- EXPECT_EQ(cap.get(CAP_PROP_N_THREADS), 0.0);
- EXPECT_EQ(cap.get(CAP_PROP_FRAME_HEIGHT), 384.0);
- EXPECT_EQ(cap.get(CAP_PROP_FRAME_WIDTH), 672.0);
- EXPECT_EQ(cap.get(CAP_PROP_FRAME_COUNT), 125);
- EXPECT_EQ(cap.get(CAP_PROP_FPS), 24.0);
- ffmpeg_check_read_raw(cap);
- }
- TEST(videoio_ffmpeg, create_with_property)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- string video_file = findDataFile("video/big_buck_bunny.mp4");
- VideoCapture cap(video_file, CAP_FFMPEG, {
- CAP_PROP_FORMAT, -1 // demux only
- });
- // confirm properties are returned without initializing AVCodecContext
- EXPECT_TRUE(cap.get(CAP_PROP_FORMAT) == -1);
- EXPECT_EQ(static_cast<int>(cap.get(CAP_PROP_FOURCC)), fourccFromString("FMP4"));
- EXPECT_EQ(cap.get(CAP_PROP_N_THREADS), 0.0);
- EXPECT_EQ(cap.get(CAP_PROP_FRAME_HEIGHT), 384.0);
- EXPECT_EQ(cap.get(CAP_PROP_FRAME_WIDTH), 672.0);
- EXPECT_EQ(cap.get(CAP_PROP_FRAME_COUNT), 125);
- EXPECT_EQ(cap.get(CAP_PROP_FPS), 24.0);
- ffmpeg_check_read_raw(cap);
- }
- TEST(videoio_ffmpeg, create_with_property_badarg)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- string video_file = findDataFile("video/big_buck_bunny.mp4");
- VideoCapture cap(video_file, CAP_FFMPEG, {
- CAP_PROP_FORMAT, -2 // invalid
- });
- EXPECT_FALSE(cap.isOpened());
- }
- // related issue: https://github.com/opencv/opencv/issues/16821
- TEST(videoio_ffmpeg, DISABLED_open_from_web)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- string video_file = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
- VideoCapture cap(video_file, CAP_FFMPEG);
- int n_frames = -1;
- EXPECT_NO_THROW(n_frames = (int)cap.get(CAP_PROP_FRAME_COUNT));
- EXPECT_EQ((int)14315, n_frames);
- }
- typedef tuple<string, string, bool, bool> FourCC_Ext_Color_Support;
- typedef testing::TestWithParam< FourCC_Ext_Color_Support > videoio_ffmpeg_16bit;
- TEST_P(videoio_ffmpeg_16bit, basic)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- const int fourcc = fourccFromString(get<0>(GetParam()));
- const string ext = string(".") + get<1>(GetParam());
- const bool isColor = get<2>(GetParam());
- const bool isSupported = get<3>(GetParam());
- const int cn = isColor ? 3 : 1;
- const int dataType = CV_16UC(cn);
- const string filename = tempfile(ext.c_str());
- const Size sz(640, 480);
- const double fps = 30.0;
- const double time_sec = 1;
- const int numFrames = static_cast<int>(fps * time_sec);
- {
- VideoWriter writer;
- writer.open(filename, CAP_FFMPEG, fourcc, fps, sz,
- {
- VIDEOWRITER_PROP_DEPTH, CV_16U,
- VIDEOWRITER_PROP_IS_COLOR, isColor
- });
- ASSERT_EQ(isSupported, writer.isOpened());
- if (isSupported)
- {
- Mat img(sz, dataType, Scalar::all(0));
- const int coeff = cvRound(min(sz.width, sz.height)/(fps * time_sec));
- for (int i = 0 ; i < numFrames; i++ )
- {
- 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;
- }
- writer.release();
- EXPECT_GT(getFileSize(filename), 8192);
- }
- }
- if (isSupported)
- {
- VideoCapture cap;
- ASSERT_TRUE(cap.open(filename, CAP_FFMPEG, {CAP_PROP_CONVERT_RGB, false}));
- ASSERT_TRUE(cap.isOpened());
- Mat img;
- bool res = true;
- int numRead = 0;
- while(res)
- {
- res = cap.read(img);
- if (res)
- {
- ++numRead;
- ASSERT_EQ(img.type(), dataType);
- ASSERT_EQ(img.size(), sz);
- }
- }
- ASSERT_EQ(numRead, numFrames);
- remove(filename.c_str());
- }
- }
- const FourCC_Ext_Color_Support sixteen_bit_modes[] =
- {
- // 16-bit grayscale is supported
- make_tuple("FFV1", "avi", false, true),
- make_tuple("FFV1", "mkv", false, true),
- // 16-bit color formats are NOT supported
- make_tuple("FFV1", "avi", true, false),
- make_tuple("FFV1", "mkv", true, false),
- };
- inline static std::string videoio_ffmpeg_16bit_name_printer(const testing::TestParamInfo<videoio_ffmpeg_16bit::ParamType>& info)
- {
- std::ostringstream os;
- os << get<0>(info.param) << "_"
- << get<1>(info.param) << "_"
- << (get<2>(info.param) ? "COLOR" : "GRAY") << "_"
- << (get<3>(info.param) ? "SUP" : "NOT");
- return os.str();
- }
- INSTANTIATE_TEST_CASE_P(/**/, videoio_ffmpeg_16bit, testing::ValuesIn(sixteen_bit_modes), videoio_ffmpeg_16bit_name_printer);
- typedef tuple<int /*inputType*/, int /*Depth*/, bool /*isColor*/, bool /*isValid*/, string /*description*/> ChannelMismatchTestParams;
- typedef testing::TestWithParam< ChannelMismatchTestParams > videoio_ffmpeg_channel_mismatch;
- TEST_P(videoio_ffmpeg_channel_mismatch, basic)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- const string filename = "mismatch_video.mp4";
- int input_type = get<0>(GetParam());
- int depth = get<1>(GetParam());
- bool is_Color = get<2>(GetParam());
- bool is_valid = get<3>(GetParam());
- const string description = get<4>(GetParam());
- const double fps = 15.0;
- const int fourcc = VideoWriter::fourcc('m', 'p', '4', 'v');
- const Mat frame(480, 640, input_type, Scalar::all(0));
- VideoWriter writer(filename, fourcc, fps, frame.size(),
- {
- cv::VIDEOWRITER_PROP_DEPTH, depth,
- VIDEOWRITER_PROP_IS_COLOR, is_Color
- });
- if (!writer.isOpened())
- throw SkipTestException("Failed to open video writer");
- for (int i = 1; i <= 15; i++)
- {
- // In case of mismatch between input frame channels and
- // expected depth/isColor configuration a warning should be printed communicating it
- writer.write(frame);
- }
- writer.release();
- VideoCapture cap(filename, CAP_FFMPEG);
- if (is_valid) {
- ASSERT_TRUE(cap.isOpened()) << "Can't open video for " << description;
- EXPECT_EQ(cap.get(CAP_PROP_FRAME_COUNT), 15) << "All frames should be written for: " << description;
- } else {
- ASSERT_FALSE(cap.isOpened()) << "Video capture should fail to open for: " << description;
- }
- std::remove(filename.c_str());
- }
- const ChannelMismatchTestParams mismatch_cases[] =
- {
- // Testing input frame channels and expected depth/isColor combinations
- // Open VideoWriter depth/isColor combination: CV_8U/true, everything with 3 channels should be valid
- make_tuple(CV_16UC1, CV_8U, true, false, "input_CV_16UC1_expected_CV_8U_isColor_true"),
- make_tuple(CV_8UC1, CV_8U, true, false, "input_CV_8UC1_expected_CV_8U_isColor_true"),
- make_tuple(CV_8UC3, CV_8U, true, true, "input_CV_8UC3_expected_CV_8U_isColor_true_valid"),
- make_tuple(CV_16UC3, CV_8U, true, true, "input_CV_16UC3_expected_CV_8U_isColor_true_valid"),
- // Open VideoWriter depth/isColor combination: 16U,8U/false, everything with 1 channel should be valid
- make_tuple(CV_8UC3, CV_8U, false, false, "input_CV_8UC3_expected_CV_8U_isColor_false"),
- make_tuple(CV_16UC3, CV_8U, false, false, "input_CV_16UC3_expected_CV_8U_isColor_false"),
- make_tuple(CV_8UC3, CV_16U, false, false, "input_CV_8UC3_expected_CV_16U_isColor_false"),
- make_tuple(CV_16UC3, CV_16U, false, false, "input_CV_16UC3_expected_CV_16U_isColor_false"),
- make_tuple(CV_8UC1, CV_16U, false, true, "input_CV_8UC1_expected_CV_16U_isColor_false_valid"),
- make_tuple(CV_16UC1, CV_8U, false, true, "input_CV_16UC1_expected_CV_8U_isColor_false_valid"),
- };
- inline static std::string videoio_ffmpeg_mismatch_name_printer(const testing::TestParamInfo<videoio_ffmpeg_channel_mismatch::ParamType>& info)
- {
- std::ostringstream os;
- os << get<4>(info.param);
- return os.str();
- }
- INSTANTIATE_TEST_CASE_P(/**/, videoio_ffmpeg_channel_mismatch, testing::ValuesIn(mismatch_cases), videoio_ffmpeg_mismatch_name_printer);
- // related issue: https://github.com/opencv/opencv/issues/23088
- TEST(ffmpeg_cap_properties, set_pos_get_msec)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- string video_file = findDataFile("video/big_buck_bunny.mp4");
- VideoCapture cap;
- EXPECT_NO_THROW(cap.open(video_file, CAP_FFMPEG));
- ASSERT_TRUE(cap.isOpened()) << "Can't open the video";
- cap.set(CAP_PROP_POS_FRAMES, 25);
- EXPECT_EQ(cap.get(CAP_PROP_POS_MSEC), 1000.0);
- cap.set(CAP_PROP_POS_MSEC, 525);
- EXPECT_EQ(cap.get(CAP_PROP_POS_MSEC), 500.0);
- cap.set(CAP_PROP_POS_AVI_RATIO, 0);
- EXPECT_EQ(cap.get(CAP_PROP_POS_MSEC), 0.0);
- }
- // Test that seeking twice to the same frame in videos with negative DTS
- // does not result in negative position or timestamp values
- // related issue: https://github.com/opencv/opencv/issues/27819
- TEST(videoio_ffmpeg, seek_with_negative_dts)
- {
- if (!videoio_registry::hasBackend(CAP_FFMPEG))
- throw SkipTestException("FFmpeg backend was not found");
- const std::string filename = findDataFile("video/negdts_h264.mp4");
- VideoCapture cap(filename, CAP_FFMPEG);
- if (!cap.isOpened())
- throw SkipTestException("Video stream is not supported");
- // after open, a single grab() should not yield negative POS_MSEC.
- ASSERT_TRUE(cap.grab());
- EXPECT_GE(cap.get(CAP_PROP_POS_MSEC), 0.0) << "Negative ts immediately after open+grab()";
- ASSERT_TRUE(cap.set(CAP_PROP_POS_FRAMES, 0));
- (void)cap.get(CAP_PROP_POS_FRAMES);
- const int framesToProbe[] = {2, 3, 4, 5};
- for (int f : framesToProbe)
- {
- // Reset to frame 0
- ASSERT_TRUE(cap.set(CAP_PROP_POS_FRAMES, 0));
- cap.get(CAP_PROP_POS_FRAMES);
- // Seek to target frame
- ASSERT_TRUE(cap.set(CAP_PROP_POS_FRAMES, f));
- const double posAfterFirstSeek = cap.get(CAP_PROP_POS_FRAMES);
- // Seek to the same frame again
- ASSERT_TRUE(cap.set(CAP_PROP_POS_FRAMES, f));
- const double posAfterSecondSeek = cap.get(CAP_PROP_POS_FRAMES);
- const double tsAfterSecondSeek = cap.get(CAP_PROP_POS_MSEC);
- EXPECT_GE(posAfterSecondSeek, 0)
- << "Frame index became negative after second seek to frame " << f
- << " (first seek gave " << posAfterFirstSeek << ")";
- EXPECT_GE(tsAfterSecondSeek, 0.0)
- << "Timestamp became negative after second seek to frame " << f;
- // Per-iteration decode check: grab() + ts non-negative
- ASSERT_TRUE(cap.grab());
- EXPECT_GE(cap.get(CAP_PROP_POS_MSEC), 0.0) << "Negative timestamp after grab() at frame " << f;
- // Verify that reading a frame works and position advances
- Mat frame;
- ASSERT_TRUE(cap.read(frame));
- ASSERT_FALSE(frame.empty());
- EXPECT_GE(cap.get(CAP_PROP_POS_FRAMES), f);
- }
- }
- }} // namespace
|