mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
449 lines
14 KiB
449 lines
14 KiB
/*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; |
|
int apiPref; |
|
protected: |
|
Videoio_Test_Base() {} |
|
virtual ~Videoio_Test_Base() {} |
|
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; 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 = 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 (apiPref == CAP_AVFOUNDATION) |
|
{ |
|
// TODO: fix this backend |
|
std::cout << "SKIP test: AVFoundation backend returns invalid frame count" << std::endl; |
|
return; |
|
} |
|
else if (apiPref == CAP_VFW) |
|
{ |
|
// TODO: fix this backend |
|
std::cout << "SKIP test: Video for Windows backend not open files" << std::endl; |
|
return; |
|
} |
|
|
|
VideoCapture cap(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 = (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"); |
|
for (int k = 0; k < n_frames; ++k) |
|
{ |
|
checkFrameRead(k, cap); |
|
} |
|
} |
|
bool 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") |
|
{ |
|
SCOPED_TRACE("progressive seek"); |
|
ASSERT_TRUE(cap.set(CAP_PROP_POS_FRAMES, 0)); |
|
for (int k = 0; k < n_frames; k += 20) |
|
{ |
|
checkFrameSeek(k, cap); |
|
} |
|
} |
|
|
|
if (ext != "mpg" && ext != "wmv") |
|
{ |
|
SCOPED_TRACE("random seek"); |
|
ASSERT_TRUE(cap.set(CAP_PROP_POS_FRAMES, 0)); |
|
for (int k = 0; k < 10; ++k) |
|
{ |
|
checkFrameSeek(cvtest::TS::ptr()->get_rng().uniform(0, n_frames), cap); |
|
} |
|
} |
|
} |
|
}; |
|
|
|
//================================================================================================== |
|
typedef tuple<string, int> 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 (apiPref == CAP_AVFOUNDATION) |
|
{ |
|
// TODO: fix this backend |
|
std::cout << "SKIP test: AVFoundation backend returns invalid frame count" << std::endl; |
|
return; |
|
} |
|
else if (apiPref == CAP_VFW) |
|
{ |
|
// TODO: fix this backend |
|
std::cout << "SKIP test: Video for Windows backend not open files" << std::endl; |
|
return; |
|
} |
|
|
|
VideoCapture cap(video_file, apiPref); |
|
if (!cap.isOpened()) |
|
{ |
|
std::cout << "SKIP test: backend " << apiPref << " can't open the video: " << video_file << std::endl; |
|
return; |
|
} |
|
|
|
EXPECT_EQ(bunny_param.getWidth() , cap.get(CAP_PROP_FRAME_WIDTH)); |
|
EXPECT_EQ(bunny_param.getHeight(), cap.get(CAP_PROP_FRAME_HEIGHT)); |
|
|
|
double 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; |
|
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; |
|
cap >> frame; |
|
if (frame.empty()) |
|
break; |
|
EXPECT_EQ(bunny_param.getWidth(), frame.cols); |
|
EXPECT_EQ(bunny_param.getHeight(), frame.rows); |
|
count_actual += 1; |
|
} |
|
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; |
|
} |
|
}; |
|
|
|
typedef tuple<string, string, float, int> Ext_Fourcc_PSNR; |
|
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 ¶m = get<1>(GetParam()); |
|
ext = get<0>(param); |
|
fourcc = fourccFromString(get<1>(param)); |
|
PSNR_GT = get<2>(param); |
|
video_file = cv::tempfile((fourccToString(fourcc) + "." + ext).c_str()); |
|
frame_count = 100; |
|
fps = 25.; |
|
apiPref = get<3>(param); |
|
} |
|
void SetUp() |
|
{ |
|
|
|
if (apiPref == CAP_AVFOUNDATION) |
|
{ |
|
// TODO: fix this backend |
|
std::cout << "SKIP test: AVFoundation backend can not write video" << std::endl; |
|
return; |
|
} |
|
else if (apiPref == CAP_VFW) |
|
{ |
|
// TODO: fix this backend |
|
std::cout << "SKIP test: Video for Windows backend not open files" << std::endl; |
|
return; |
|
} |
|
Mat img(frame_size, CV_8UC3); |
|
VideoWriter writer(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); |
|
writer << img; |
|
} |
|
writer.release(); |
|
} |
|
void TearDown() |
|
{ |
|
remove(video_file.c_str()); |
|
} |
|
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; |
|
|
|
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 |
|
} |
|
}; |
|
|
|
//================================================================================================== |
|
|
|
int backend_params[] = { |
|
#ifdef HAVE_QUICKTIME |
|
CAP_QT, |
|
#endif |
|
|
|
#ifdef HAVE_AVFOUNDATION |
|
CAP_AVFOUNDATION, |
|
#endif |
|
|
|
#ifdef HAVE_MSMF |
|
CAP_MSMF, |
|
#endif |
|
|
|
#ifdef HAVE_VFW |
|
CAP_VFW, |
|
#endif |
|
|
|
#ifdef HAVE_GSTREAMER |
|
CAP_GSTREAMER, |
|
#endif |
|
|
|
#ifdef HAVE_FFMPEG |
|
CAP_FFMPEG, |
|
#endif |
|
CAP_OPENCV_MJPEG |
|
// CAP_INTEL_MFX |
|
}; |
|
|
|
string bunny_params[] = { |
|
#ifdef HAVE_VIDEO_INPUT |
|
string("wmv"), |
|
string("mov"), |
|
string("mp4"), |
|
string("mpg"), |
|
string("avi"), |
|
#endif |
|
string("mjpg.avi") |
|
}; |
|
|
|
TEST_P(Videoio_Bunny, read_position) { doTest(); } |
|
|
|
TEST_P(Videoio_Bunny, frame_count) { doFrameCountTest(); } |
|
|
|
INSTANTIATE_TEST_CASE_P(videoio, Videoio_Bunny, |
|
testing::Combine( |
|
testing::ValuesIn(bunny_params), |
|
testing::ValuesIn(backend_params))); |
|
|
|
|
|
//================================================================================================== |
|
|
|
inline Ext_Fourcc_PSNR makeParam(const char * ext, const char * fourcc, float psnr, int apipref) |
|
{ |
|
return make_tuple(string(ext), string(fourcc), (float)psnr, (int)apipref); |
|
} |
|
|
|
Ext_Fourcc_PSNR synthetic_params[] = { |
|
|
|
#ifdef HAVE_MSMF |
|
#if !defined(_M_ARM) |
|
makeParam("wmv", "WMV1", 30.f, CAP_MSMF), |
|
makeParam("wmv", "WMV2", 30.f, CAP_MSMF), |
|
#endif |
|
makeParam("wmv", "WMV3", 30.f, CAP_MSMF), |
|
makeParam("wmv", "WVC1", 30.f, CAP_MSMF), |
|
makeParam("avi", "H264", 30.f, CAP_MSMF), |
|
makeParam("avi", "MJPG", 30.f, CAP_MSMF), |
|
#endif |
|
|
|
#ifdef HAVE_VFW |
|
#if !defined(_M_ARM) |
|
makeParam("wmv", "WMV1", 30.f, CAP_VFW), |
|
makeParam("wmv", "WMV2", 30.f, CAP_VFW), |
|
#endif |
|
makeParam("wmv", "WMV3", 30.f, CAP_VFW), |
|
makeParam("wmv", "WVC1", 30.f, CAP_VFW), |
|
makeParam("avi", "H264", 30.f, CAP_VFW), |
|
makeParam("avi", "MJPG", 30.f, CAP_VFW), |
|
#endif |
|
|
|
#ifdef HAVE_QUICKTIME |
|
makeParam("mov", "mp4v", 30.f, CAP_QT), |
|
makeParam("avi", "XVID", 30.f, CAP_QT), |
|
makeParam("avi", "MPEG", 30.f, CAP_QT), |
|
makeParam("avi", "IYUV", 30.f, CAP_QT), |
|
makeParam("avi", "MJPG", 30.f, CAP_QT), |
|
|
|
makeParam("mkv", "XVID", 30.f, CAP_QT), |
|
makeParam("mkv", "MPEG", 30.f, CAP_QT), |
|
makeParam("mkv", "MJPG", 30.f, CAP_QT), |
|
#endif |
|
|
|
#ifdef HAVE_AVFOUNDATION |
|
makeParam("mov", "mp4v", 30.f, CAP_AVFOUNDATION), |
|
makeParam("avi", "XVID", 30.f, CAP_AVFOUNDATION), |
|
makeParam("avi", "MPEG", 30.f, CAP_AVFOUNDATION), |
|
makeParam("avi", "IYUV", 30.f, CAP_AVFOUNDATION), |
|
makeParam("avi", "MJPG", 30.f, CAP_AVFOUNDATION), |
|
|
|
makeParam("mkv", "XVID", 30.f, CAP_AVFOUNDATION), |
|
makeParam("mkv", "MPEG", 30.f, CAP_AVFOUNDATION), |
|
makeParam("mkv", "MJPG", 30.f, CAP_AVFOUNDATION), |
|
#endif |
|
|
|
#ifdef HAVE_FFMPEG |
|
makeParam("avi", "XVID", 30.f, CAP_FFMPEG), |
|
makeParam("avi", "MPEG", 30.f, CAP_FFMPEG), |
|
makeParam("avi", "IYUV", 30.f, CAP_FFMPEG), |
|
makeParam("avi", "MJPG", 30.f, CAP_FFMPEG), |
|
|
|
makeParam("mkv", "XVID", 30.f, CAP_FFMPEG), |
|
makeParam("mkv", "MPEG", 30.f, CAP_FFMPEG), |
|
makeParam("mkv", "MJPG", 30.f, CAP_FFMPEG), |
|
#endif |
|
|
|
#ifdef HAVE_GSTREAMER |
|
// makeParam("avi", "XVID", 30.f, CAP_GSTREAMER), - corrupted frames, broken indexes |
|
makeParam("avi", "MPEG", 30.f, CAP_GSTREAMER), |
|
makeParam("avi", "IYUV", 30.f, CAP_GSTREAMER), |
|
makeParam("avi", "MJPG", 30.f, CAP_GSTREAMER), |
|
makeParam("avi", "H264", 30.f, CAP_GSTREAMER), |
|
|
|
// makeParam("mkv", "XVID", 30.f, CAP_GSTREAMER), |
|
makeParam("mkv", "MPEG", 30.f, CAP_GSTREAMER), |
|
makeParam("mkv", "MJPG", 30.f, CAP_GSTREAMER), |
|
|
|
#endif |
|
makeParam("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))); |
|
|
|
} // namespace
|
|
|