Path: blob/master/modules/videoio/test/test_video_io.cpp
16339 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009, Willow Garage Inc., all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142#include "test_precomp.hpp"43#include "opencv2/videoio/videoio_c.h"4445namespace opencv_test46{4748class Videoio_Test_Base49{50protected:51string ext;52string video_file;53VideoCaptureAPIs apiPref;54protected:55Videoio_Test_Base() {}56virtual ~Videoio_Test_Base() {}57virtual void checkFrameContent(Mat &, int) {}58virtual void checkFrameCount(int &) {}59void checkFrameRead(int idx, VideoCapture & cap)60{61//int frameID = (int)cap.get(CAP_PROP_POS_FRAMES);62Mat img;63ASSERT_NO_THROW(cap >> img);64//std::cout << "idx=" << idx << " img=" << img.size() << " frameID=" << frameID << std::endl;65ASSERT_FALSE(img.empty()) << "idx=" << idx;66checkFrameContent(img, idx);67}68void checkFrameSeek(int idx, VideoCapture & cap)69{70bool canSeek = false;71ASSERT_NO_THROW(canSeek = cap.set(CAP_PROP_POS_FRAMES, idx));72if (!canSeek)73{74std::cout << "Seek to frame '" << idx << "' is not supported. SKIP." << std::endl;75return;76}77EXPECT_EQ(idx, (int)cap.get(CAP_PROP_POS_FRAMES));78checkFrameRead(idx, cap);79}80public:81void doTest()82{83if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))84throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));85VideoCapture cap;86ASSERT_NO_THROW(cap.open(video_file, apiPref));87if (!cap.isOpened())88{89std::cout << "SKIP test: backend " << apiPref << " can't open the video: " << video_file << std::endl;90return;91}92int n_frames = -1;93EXPECT_NO_THROW(n_frames = (int)cap.get(CAP_PROP_FRAME_COUNT));94if (n_frames > 0)95{96ASSERT_GT(n_frames, 0);97checkFrameCount(n_frames);98}99else100{101std::cout << "CAP_PROP_FRAME_COUNT is not supported by backend. Assume 50 frames." << std::endl;102n_frames = 50;103}104105{106SCOPED_TRACE("consecutive read");107if (apiPref == CAP_GSTREAMER)108{109// This workaround is for GStreamer 1.3.1.1 and older.110// Old Gstreamer has a bug which handles the total duration 1 frame shorter111// Old Gstreamer are used in Ubuntu 14.04, so the following code could be removed after it's EOL112n_frames--;113}114for (int k = 0; k < n_frames; ++k)115{116checkFrameRead(k, cap);117}118}119bool canSeek = false;120EXPECT_NO_THROW(canSeek = cap.set(CAP_PROP_POS_FRAMES, 0));121if (!canSeek)122{123std::cout << "Seek to frame '0' is not supported. SKIP all 'seek' tests." << std::endl;124return;125}126127if (ext != "wmv" && ext != "h264" && ext != "h265")128{129SCOPED_TRACE("progressive seek");130bool res = false;131EXPECT_NO_THROW(res = cap.set(CAP_PROP_POS_FRAMES, 0));132ASSERT_TRUE(res);133for (int k = 0; k < n_frames; k += 20)134{135checkFrameSeek(k, cap);136}137}138139if (ext != "mpg" && ext != "wmv" && ext != "h264" && ext != "h265")140{141SCOPED_TRACE("random seek");142bool res = false;143EXPECT_NO_THROW(res = cap.set(CAP_PROP_POS_FRAMES, 0));144ASSERT_TRUE(res);145for (int k = 0; k < 10; ++k)146{147checkFrameSeek(cvtest::TS::ptr()->get_rng().uniform(0, n_frames), cap);148}149}150}151};152153//==================================================================================================154typedef tuple<string, VideoCaptureAPIs> Backend_Type_Params;155156class Videoio_Bunny : public Videoio_Test_Base, public testing::TestWithParam<Backend_Type_Params>157{158BunnyParameters bunny_param;159public:160Videoio_Bunny()161{162ext = get<0>(GetParam());163apiPref = get<1>(GetParam());164video_file = BunnyParameters::getFilename(String(".") + ext);165}166void doFrameCountTest()167{168if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))169throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));170VideoCapture cap;171EXPECT_NO_THROW(cap.open(video_file, apiPref));172if (!cap.isOpened())173{174std::cout << "SKIP test: backend " << apiPref << " can't open the video: " << video_file << std::endl;175return;176}177178Size actual;179EXPECT_NO_THROW(actual = Size((int)cap.get(CAP_PROP_FRAME_WIDTH),180(int)cap.get(CAP_PROP_FRAME_HEIGHT)));181EXPECT_EQ(bunny_param.getWidth(), actual.width);182EXPECT_EQ(bunny_param.getHeight(), actual.height);183184double fps_prop = 0;185EXPECT_NO_THROW(fps_prop = cap.get(CAP_PROP_FPS));186if (fps_prop > 0)187EXPECT_NEAR(fps_prop, bunny_param.getFps(), 1);188else189std::cout << "FPS is not available. SKIP check." << std::endl;190191int count_prop = 0;192EXPECT_NO_THROW(count_prop = (int)cap.get(CAP_PROP_FRAME_COUNT));193// mpg file reports 5.08 sec * 24 fps => property returns 122 frames194// but actual number of frames returned is 125195if (ext != "mpg")196{197if (count_prop > 0)198{199EXPECT_EQ(bunny_param.getCount(), count_prop);200}201}202203int count_actual = 0;204while (cap.isOpened())205{206Mat frame;207EXPECT_NO_THROW(cap >> frame);208if (frame.empty())209break;210EXPECT_EQ(bunny_param.getWidth(), frame.cols);211EXPECT_EQ(bunny_param.getHeight(), frame.rows);212count_actual += 1;213}214if (count_prop > 0)215{216EXPECT_NEAR(bunny_param.getCount(), count_actual, 1);217}218else219std::cout << "Frames counter is not available. Actual frames: " << count_actual << ". SKIP check." << std::endl;220}221};222223//==================================================================================================224225struct Ext_Fourcc_PSNR226{227string ext;228string fourcc;229float PSNR;230VideoCaptureAPIs api;231};232typedef tuple<Size, Ext_Fourcc_PSNR> Size_Ext_Fourcc_PSNR;233234class Videoio_Synthetic : public Videoio_Test_Base, public testing::TestWithParam<Size_Ext_Fourcc_PSNR>235{236Size frame_size;237int fourcc;238float PSNR_GT;239int frame_count;240double fps;241public:242Videoio_Synthetic()243{244frame_size = get<0>(GetParam());245const Ext_Fourcc_PSNR p = get<1>(GetParam());246ext = p.ext;247fourcc = fourccFromString(p.fourcc);248PSNR_GT = p.PSNR;249video_file = cv::tempfile((fourccToString(fourcc) + "." + ext).c_str());250frame_count = 100;251fps = 25.;252apiPref = p.api;253}254void SetUp()255{256Mat img(frame_size, CV_8UC3);257VideoWriter writer;258EXPECT_NO_THROW(writer.open(video_file, apiPref, fourcc, fps, frame_size, true));259ASSERT_TRUE(writer.isOpened());260for(int i = 0; i < frame_count; ++i )261{262generateFrame(i, frame_count, img);263EXPECT_NO_THROW(writer << img);264}265EXPECT_NO_THROW(writer.release());266}267void TearDown()268{269remove(video_file.c_str());270}271virtual void checkFrameContent(Mat & img, int idx)272{273Mat imgGT(frame_size, CV_8UC3);274generateFrame(idx, frame_count, imgGT);275double psnr = cvtest::PSNR(img, imgGT);276ASSERT_GT(psnr, PSNR_GT) << "frame " << idx;277}278virtual void checkFrameCount(int &actual)279{280Range expected_frame_count = Range(frame_count, frame_count);281282// Hack! Newer FFmpeg versions in this combination produce a file283// whose reported duration is one frame longer than needed, and so284// the calculated frame count is also off by one. Ideally, we'd want285// to fix both writing (to produce the correct duration) and reading286// (to correctly report frame count for such files), but I don't know287// how to do either, so this is a workaround for now.288if (fourcc == VideoWriter::fourcc('M', 'P', 'E', 'G') && ext == "mkv")289expected_frame_count.end += 1;290291// Workaround for some gstreamer pipelines292if (apiPref == CAP_GSTREAMER)293expected_frame_count.start -= 1;294295ASSERT_LE(expected_frame_count.start, actual);296ASSERT_GE(expected_frame_count.end, actual);297298actual = expected_frame_count.start; // adjust actual frame boundary to possible minimum299}300};301302//==================================================================================================303304static const VideoCaptureAPIs backend_params[] = {305#ifdef HAVE_QUICKTIME306CAP_QT,307#endif308309// TODO: Broken?310//#ifdef HAVE_AVFOUNDATION311// CAP_AVFOUNDATION,312//#endif313314#ifdef HAVE_MSMF315CAP_MSMF,316#endif317318// TODO: Broken?319//#ifdef HAVE_VFW320// CAP_VFW,321//#endif322323#ifdef HAVE_GSTREAMER324CAP_GSTREAMER,325#endif326327#ifdef HAVE_FFMPEG328CAP_FFMPEG,329#endif330331#ifdef HAVE_XINE332CAP_XINE,333#endif334335CAP_OPENCV_MJPEG336// CAP_INTEL_MFX337};338339static const string bunny_params[] = {340#ifdef HAVE_VIDEO_INPUT341string("wmv"),342string("mov"),343string("mp4"),344string("mpg"),345string("avi"),346string("h264"),347string("h265"),348#endif349string("mjpg.avi")350};351352TEST_P(Videoio_Bunny, read_position) { doTest(); }353354TEST_P(Videoio_Bunny, frame_count) { doFrameCountTest(); }355356INSTANTIATE_TEST_CASE_P(videoio, Videoio_Bunny,357testing::Combine(358testing::ValuesIn(bunny_params),359testing::ValuesIn(backend_params)));360361362//==================================================================================================363364inline Ext_Fourcc_PSNR makeParam(const char * ext, const char * fourcc, float psnr, VideoCaptureAPIs apipref)365{366Ext_Fourcc_PSNR res;367res.ext = ext;368res.fourcc = fourcc;369res.PSNR = psnr;370res.api = apipref;371return res;372}373374inline static std::ostream &operator<<(std::ostream &out, const Ext_Fourcc_PSNR &p)375{376out << "FOURCC(" << p.fourcc << "), ." << p.ext << ", " << p.api << ", " << p.PSNR << "dB"; return out;377}378379static Ext_Fourcc_PSNR synthetic_params[] = {380381#ifdef HAVE_MSMF382#if !defined(_M_ARM)383makeParam("wmv", "WMV1", 30.f, CAP_MSMF),384makeParam("wmv", "WMV2", 30.f, CAP_MSMF),385#endif386makeParam("wmv", "WMV3", 30.f, CAP_MSMF),387makeParam("wmv", "WVC1", 30.f, CAP_MSMF),388makeParam("mov", "H264", 30.f, CAP_MSMF),389#endif390391// TODO: Broken?392//#ifdef HAVE_VFW393//#if !defined(_M_ARM)394// makeParam("wmv", "WMV1", 30.f, CAP_VFW),395// makeParam("wmv", "WMV2", 30.f, CAP_VFW),396//#endif397// makeParam("wmv", "WMV3", 30.f, CAP_VFW),398// makeParam("wmv", "WVC1", 30.f, CAP_VFW),399// makeParam("avi", "H264", 30.f, CAP_VFW),400// makeParam("avi", "MJPG", 30.f, CAP_VFW),401//#endif402403#ifdef HAVE_QUICKTIME404makeParam("mov", "mp4v", 30.f, CAP_QT),405makeParam("avi", "XVID", 30.f, CAP_QT),406makeParam("avi", "MPEG", 30.f, CAP_QT),407makeParam("avi", "IYUV", 30.f, CAP_QT),408makeParam("avi", "MJPG", 30.f, CAP_QT),409410makeParam("mkv", "XVID", 30.f, CAP_QT),411makeParam("mkv", "MPEG", 30.f, CAP_QT),412makeParam("mkv", "MJPG", 30.f, CAP_QT),413#endif414415// TODO: Broken?416//#ifdef HAVE_AVFOUNDATION417// makeParam("mov", "mp4v", 30.f, CAP_AVFOUNDATION),418// makeParam("avi", "XVID", 30.f, CAP_AVFOUNDATION),419// makeParam("avi", "MPEG", 30.f, CAP_AVFOUNDATION),420// makeParam("avi", "IYUV", 30.f, CAP_AVFOUNDATION),421// makeParam("avi", "MJPG", 30.f, CAP_AVFOUNDATION),422423// makeParam("mkv", "XVID", 30.f, CAP_AVFOUNDATION),424// makeParam("mkv", "MPEG", 30.f, CAP_AVFOUNDATION),425// makeParam("mkv", "MJPG", 30.f, CAP_AVFOUNDATION),426//#endif427428#ifdef HAVE_FFMPEG429makeParam("avi", "XVID", 30.f, CAP_FFMPEG),430makeParam("avi", "MPEG", 30.f, CAP_FFMPEG),431makeParam("avi", "IYUV", 30.f, CAP_FFMPEG),432makeParam("avi", "MJPG", 30.f, CAP_FFMPEG),433434makeParam("mkv", "XVID", 30.f, CAP_FFMPEG),435makeParam("mkv", "MPEG", 30.f, CAP_FFMPEG),436makeParam("mkv", "MJPG", 30.f, CAP_FFMPEG),437#endif438439#ifdef HAVE_GSTREAMER440makeParam("avi", "MPEG", 30.f, CAP_GSTREAMER),441makeParam("avi", "MJPG", 30.f, CAP_GSTREAMER),442makeParam("avi", "H264", 30.f, CAP_GSTREAMER),443444makeParam("mkv", "MPEG", 30.f, CAP_GSTREAMER),445makeParam("mkv", "MJPG", 30.f, CAP_GSTREAMER),446makeParam("mkv", "H264", 30.f, CAP_GSTREAMER),447448#endif449makeParam("avi", "MJPG", 30.f, CAP_OPENCV_MJPEG),450};451452453Size all_sizes[] = {454Size(640, 480),455Size(976, 768)456};457458TEST_P(Videoio_Synthetic, write_read_position) { doTest(); }459460INSTANTIATE_TEST_CASE_P(videoio, Videoio_Synthetic,461testing::Combine(462testing::ValuesIn(all_sizes),463testing::ValuesIn(synthetic_params)));464465} // namespace466467468