vendor: OpenCV 5.0.0 snapshot at 40738fb16ceddb5fb3fea747585f7ce6abb0605b
This commit is contained in:
@@ -0,0 +1,370 @@
|
||||
// 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"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
//file name, number of audio channels, epsilon, video type, weight, height, number of frame, number of audio samples, fps, psnr Threshold, backend
|
||||
typedef std::tuple<std::string, int, double, int, int, int, int, int, int, double, VideoCaptureAPIs> paramCombination;
|
||||
//file name, number of audio channels, number of audio samples, epsilon, backend
|
||||
typedef std::tuple<std::string, int, int, double, VideoCaptureAPIs> param;
|
||||
|
||||
class AudioBaseTest
|
||||
{
|
||||
protected:
|
||||
AudioBaseTest(){}
|
||||
void getValidAudioData()
|
||||
{
|
||||
const double step = 3.14/22050;
|
||||
double value = 0;
|
||||
validAudioData.resize(expectedNumAudioCh);
|
||||
for (int nCh = 0; nCh < expectedNumAudioCh; nCh++)
|
||||
{
|
||||
value = 0;
|
||||
for(unsigned int i = 0; i < numberOfSamples; i++)
|
||||
{
|
||||
if (i != 0 && i % 44100 == 0)
|
||||
value = 0;
|
||||
validAudioData[nCh].push_back(sin(value));
|
||||
value += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
void checkAudio()
|
||||
{
|
||||
getValidAudioData();
|
||||
|
||||
ASSERT_EQ(expectedNumAudioCh, (int)audioData.size());
|
||||
for (unsigned int nCh = 0; nCh < audioData.size(); nCh++)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (audioData[nCh].size() == 132924 && numberOfSamples == 131819 && fileName == "test_audio.mp4")
|
||||
throw SkipTestException("Detected failure observed on legacy Windows versions. SKIP");
|
||||
#endif
|
||||
ASSERT_EQ(numberOfSamples, audioData[nCh].size()) << "nCh=" << nCh;
|
||||
for (unsigned int i = 0; i < numberOfSamples; i++)
|
||||
{
|
||||
EXPECT_NEAR(validAudioData[nCh][i], audioData[nCh][i], epsilon) << "sample index=" << i << " nCh=" << nCh;
|
||||
}
|
||||
}
|
||||
}
|
||||
protected:
|
||||
int expectedNumAudioCh;
|
||||
unsigned int numberOfSamples;
|
||||
double epsilon;
|
||||
VideoCaptureAPIs backend;
|
||||
std::string root;
|
||||
std::string fileName;
|
||||
|
||||
std::vector<std::vector<double>> validAudioData;
|
||||
std::vector<std::vector<double>> audioData;
|
||||
std::vector<int> params;
|
||||
|
||||
Mat audioFrame;
|
||||
VideoCapture cap;
|
||||
};
|
||||
|
||||
class AudioTestFixture : public AudioBaseTest, public testing::TestWithParam <param>
|
||||
{
|
||||
public:
|
||||
AudioTestFixture()
|
||||
{
|
||||
fileName = get<0>(GetParam());
|
||||
expectedNumAudioCh = get<1>(GetParam());
|
||||
numberOfSamples = get<2>(GetParam());
|
||||
epsilon = get<3>(GetParam());
|
||||
backend = get<4>(GetParam());
|
||||
root = "audio/";
|
||||
params = { CAP_PROP_AUDIO_STREAM, 0,
|
||||
CAP_PROP_VIDEO_STREAM, -1,
|
||||
CAP_PROP_AUDIO_DATA_DEPTH, CV_16S };
|
||||
}
|
||||
|
||||
void doTest()
|
||||
{
|
||||
ASSERT_TRUE(cap.open(findDataFile(root + fileName), backend, params));
|
||||
const int audioBaseIndex = static_cast<int>(cap.get(cv::CAP_PROP_AUDIO_BASE_INDEX));
|
||||
const int numberOfChannels = (int)cap.get(CAP_PROP_AUDIO_TOTAL_CHANNELS);
|
||||
ASSERT_EQ(expectedNumAudioCh, numberOfChannels);
|
||||
double f = 0;
|
||||
audioData.resize(numberOfChannels);
|
||||
for (;;)
|
||||
{
|
||||
if (cap.grab())
|
||||
{
|
||||
for (int nCh = 0; nCh < numberOfChannels; nCh++)
|
||||
{
|
||||
ASSERT_TRUE(cap.retrieve(audioFrame, audioBaseIndex + nCh));
|
||||
ASSERT_EQ(CV_16SC1, audioFrame.type()) << audioData[nCh].size();
|
||||
for (int i = 0; i < audioFrame.cols; i++)
|
||||
{
|
||||
f = ((double) audioFrame.at<signed short>(0,i)) / (double) 32768;
|
||||
audioData[nCh].push_back(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else { break; }
|
||||
}
|
||||
ASSERT_FALSE(audioData.empty());
|
||||
|
||||
checkAudio();
|
||||
}
|
||||
};
|
||||
|
||||
const param audioParams[] =
|
||||
{
|
||||
#ifdef _WIN32
|
||||
param("test_audio.wav", 1, 132300, 0.0001, cv::CAP_MSMF),
|
||||
param("test_mono_audio.mp3", 1, 133104, 0.12, cv::CAP_MSMF),
|
||||
param("test_stereo_audio.mp3", 2, 133104, 0.12, cv::CAP_MSMF),
|
||||
param("test_audio.mp4", 1, 133104, 0.15, cv::CAP_MSMF),
|
||||
#endif
|
||||
param("test_audio.wav", 1, 132300, 0.0001, cv::CAP_GSTREAMER),
|
||||
param("test_audio.mp4", 1, 132522, 0.15, cv::CAP_GSTREAMER),
|
||||
};
|
||||
|
||||
class Audio : public AudioTestFixture{};
|
||||
|
||||
TEST_P(Audio, audio)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(cv::VideoCaptureAPIs(backend)))
|
||||
throw SkipTestException(cv::videoio_registry::getBackendName(backend) + " backend was not found");
|
||||
|
||||
doTest();
|
||||
}
|
||||
|
||||
inline static std::string Audio_name_printer(const testing::TestParamInfo<Audio::ParamType>& info)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << getExtensionSafe(get<0>(info.param)) << "_"
|
||||
<< get<1>(info.param) << "CN" << "_"
|
||||
<< getBackendNameSafe(get<4>(info.param));
|
||||
return out.str();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Audio, testing::ValuesIn(audioParams), Audio_name_printer);
|
||||
|
||||
class MediaTestFixture : public AudioBaseTest, public testing::TestWithParam <paramCombination>
|
||||
{
|
||||
public:
|
||||
MediaTestFixture():
|
||||
videoType(get<3>(GetParam())),
|
||||
height(get<4>(GetParam())),
|
||||
width(get<5>(GetParam())),
|
||||
numberOfFrames(get<6>(GetParam())),
|
||||
fps(get<8>(GetParam())),
|
||||
psnrThreshold(get<9>(GetParam()))
|
||||
{
|
||||
fileName = get<0>(GetParam());
|
||||
expectedNumAudioCh = get<1>(GetParam());
|
||||
numberOfSamples = get<7>(GetParam());
|
||||
epsilon = get<2>(GetParam());
|
||||
backend = get<10>(GetParam());
|
||||
root = "audio/";
|
||||
params = { CAP_PROP_AUDIO_STREAM, 0,
|
||||
CAP_PROP_VIDEO_STREAM, 0,
|
||||
CAP_PROP_AUDIO_DATA_DEPTH, CV_16S };
|
||||
}
|
||||
|
||||
void doTest()
|
||||
{
|
||||
ASSERT_TRUE(cap.open(findDataFile(root + fileName), backend, params));
|
||||
|
||||
const int audioBaseIndex = static_cast<int>(cap.get(cv::CAP_PROP_AUDIO_BASE_INDEX));
|
||||
const int numberOfChannels = (int)cap.get(CAP_PROP_AUDIO_TOTAL_CHANNELS);
|
||||
ASSERT_EQ(expectedNumAudioCh, numberOfChannels);
|
||||
|
||||
const int samplePerSecond = (int)cap.get(CAP_PROP_AUDIO_SAMPLES_PER_SECOND);
|
||||
ASSERT_EQ(44100, samplePerSecond);
|
||||
int samplesPerFrame = (int)(1./fps*samplePerSecond);
|
||||
|
||||
double audio0_timestamp = 0;
|
||||
|
||||
Mat videoFrame;
|
||||
Mat img(height, width, videoType);
|
||||
audioData.resize(numberOfChannels);
|
||||
for (int frame = 0; frame < numberOfFrames; frame++)
|
||||
{
|
||||
SCOPED_TRACE(cv::format("frame=%d", frame));
|
||||
|
||||
ASSERT_TRUE(cap.grab());
|
||||
if (frame == 0)
|
||||
{
|
||||
double audio_shift = cap.get(CAP_PROP_AUDIO_SHIFT_NSEC);
|
||||
double video0_timestamp = cap.get(CAP_PROP_POS_MSEC) * 1e-3;
|
||||
audio0_timestamp = video0_timestamp + audio_shift * 1e-9;
|
||||
|
||||
std::cout << "video0 timestamp: " << video0_timestamp << " audio0 timestamp: " << audio0_timestamp << " (audio shift nanoseconds: " << audio_shift << " , seconds: " << audio_shift * 1e-9 << ")" << std::endl;
|
||||
}
|
||||
ASSERT_TRUE(cap.retrieve(videoFrame));
|
||||
if (epsilon >= 0)
|
||||
{
|
||||
generateFrame(frame, numberOfFrames, img);
|
||||
ASSERT_EQ(img.size, videoFrame.size);
|
||||
#if 0 // OpenCV 5.0: need to repair old fonts in generated frames
|
||||
double psnr = cvtest::PSNR(img, videoFrame);
|
||||
EXPECT_GE(psnr, psnrThreshold);
|
||||
#endif
|
||||
}
|
||||
|
||||
int audioFrameCols = 0;
|
||||
for (int nCh = 0; nCh < numberOfChannels; nCh++)
|
||||
{
|
||||
ASSERT_TRUE(cap.retrieve(audioFrame, audioBaseIndex+nCh));
|
||||
if (audioFrame.empty())
|
||||
continue;
|
||||
ASSERT_EQ(CV_16SC1, audioFrame.type());
|
||||
if (nCh == 0)
|
||||
audioFrameCols = audioFrame.cols;
|
||||
else
|
||||
ASSERT_EQ(audioFrameCols, audioFrame.cols) << "channel "<< nCh;
|
||||
for (int i = 0; i < audioFrame.cols; i++)
|
||||
{
|
||||
double f = audioFrame.at<signed short>(0,i) / 32768.0;
|
||||
audioData[nCh].push_back(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (frame < 5 || frame >= numberOfFrames-5)
|
||||
std::cout << "frame=" << frame << ": audioFrameSize=" << audioFrameCols << " videoTimestamp=" << cap.get(CAP_PROP_POS_MSEC) << " ms" << std::endl;
|
||||
else if (frame == 6)
|
||||
std::cout << "frame..." << std::endl;
|
||||
|
||||
if (audioFrameCols == 0)
|
||||
continue;
|
||||
if (frame != 0 && frame != numberOfFrames-1)
|
||||
{
|
||||
// validate audio position
|
||||
EXPECT_NEAR(
|
||||
cap.get(CAP_PROP_AUDIO_POS) / samplePerSecond + audio0_timestamp,
|
||||
cap.get(CAP_PROP_POS_MSEC) * 1e-3,
|
||||
(1.0 / fps) * 0.6)
|
||||
<< "CAP_PROP_AUDIO_POS=" << cap.get(CAP_PROP_AUDIO_POS) << " CAP_PROP_POS_MSEC=" << cap.get(CAP_PROP_POS_MSEC);
|
||||
}
|
||||
if (frame != 0 && frame != numberOfFrames-1 && audioData[0].size() != (size_t)numberOfSamples)
|
||||
{
|
||||
if (backend == cv::CAP_MSMF)
|
||||
{
|
||||
int audioSamplesTolerance = samplesPerFrame / 2;
|
||||
// validate audio frame size
|
||||
EXPECT_NEAR(audioFrame.cols, samplesPerFrame, audioSamplesTolerance);
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_FALSE(cap.grab());
|
||||
ASSERT_FALSE(audioData.empty());
|
||||
|
||||
std::cout << "Total audio samples=" << audioData[0].size() << std::endl;
|
||||
|
||||
if (epsilon >= 0)
|
||||
checkAudio();
|
||||
}
|
||||
protected:
|
||||
const int videoType;
|
||||
const int height;
|
||||
const int width;
|
||||
const int numberOfFrames;
|
||||
const int fps;
|
||||
const double psnrThreshold;
|
||||
};
|
||||
|
||||
class Media : public MediaTestFixture{};
|
||||
|
||||
TEST_P(Media, audio)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(cv::VideoCaptureAPIs(backend)))
|
||||
throw SkipTestException(cv::videoio_registry::getBackendName(backend) + " backend was not found");
|
||||
if (cvtest::skipUnstableTests && backend == CAP_GSTREAMER)
|
||||
throw SkipTestException("Unstable GStreamer test");
|
||||
|
||||
doTest();
|
||||
}
|
||||
|
||||
const paramCombination mediaParams[] =
|
||||
{
|
||||
paramCombination("test_audio.mp4", 1, 0.15, CV_8UC3, 240, 320, 90, 132299, 30, 30., cv::CAP_GSTREAMER)
|
||||
#ifdef _WIN32
|
||||
, paramCombination("test_audio.mp4", 1, 0.15, CV_8UC3, 240, 320, 90, 131819, 30, 30., cv::CAP_MSMF)
|
||||
#if 0
|
||||
// https://filesamples.com/samples/video/mp4/sample_960x400_ocean_with_audio.mp4
|
||||
, paramCombination("sample_960x400_ocean_with_audio.mp4", 2, -1/*eplsilon*/, CV_8UC3, 400, 960, 1116, 2056588, 30, 30., cv::CAP_MSMF)
|
||||
#endif
|
||||
#endif // _WIN32
|
||||
};
|
||||
|
||||
inline static std::string Media_name_printer(const testing::TestParamInfo<Media::ParamType>& info)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << getExtensionSafe(get<0>(info.param)) << "_"
|
||||
<< get<1>(info.param) << "CN" << "_"
|
||||
<< getBackendNameSafe(get<10>(info.param));
|
||||
return out.str();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Media, testing::ValuesIn(mediaParams), Media_name_printer);
|
||||
|
||||
TEST(AudioOpenCheck, bad_arg_invalid_audio_stream)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(cv::VideoCaptureAPIs(cv::CAP_MSMF)))
|
||||
throw SkipTestException("CAP_MSMF backend was not found");
|
||||
|
||||
std::string fileName = "audio/test_audio.wav";
|
||||
std::vector<int> params {
|
||||
CAP_PROP_AUDIO_STREAM, 1,
|
||||
CAP_PROP_VIDEO_STREAM, -1, // disabled
|
||||
CAP_PROP_AUDIO_DATA_DEPTH, CV_16S
|
||||
};
|
||||
VideoCapture cap;
|
||||
cap.open(findDataFile(fileName), cv::CAP_MSMF, params);
|
||||
ASSERT_FALSE(cap.isOpened());
|
||||
}
|
||||
|
||||
TEST(AudioOpenCheck, bad_arg_invalid_audio_stream_video)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(cv::VideoCaptureAPIs(cv::CAP_MSMF)))
|
||||
throw SkipTestException("CAP_MSMF backend was not found");
|
||||
|
||||
std::string fileName = "audio/test_audio.mp4";
|
||||
std::vector<int> params {
|
||||
CAP_PROP_AUDIO_STREAM, 1,
|
||||
CAP_PROP_VIDEO_STREAM, 0,
|
||||
CAP_PROP_AUDIO_DATA_DEPTH, CV_16S
|
||||
};
|
||||
VideoCapture cap;
|
||||
cap.open(findDataFile(fileName), cv::CAP_MSMF, params);
|
||||
ASSERT_FALSE(cap.isOpened());
|
||||
}
|
||||
|
||||
|
||||
TEST(AudioOpenCheck, MSMF_bad_arg_invalid_audio_sample_per_second)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(cv::VideoCaptureAPIs(cv::CAP_MSMF)))
|
||||
throw SkipTestException("CAP_MSMF backend was not found");
|
||||
|
||||
std::string fileName = "audio/test_audio.mp4";
|
||||
std::vector<int> params {
|
||||
CAP_PROP_AUDIO_STREAM, 0,
|
||||
CAP_PROP_VIDEO_STREAM, -1, // disabled
|
||||
CAP_PROP_AUDIO_SAMPLES_PER_SECOND, (int)1e9
|
||||
};
|
||||
VideoCapture cap;
|
||||
cap.open(findDataFile(fileName), cv::CAP_MSMF, params);
|
||||
ASSERT_FALSE(cap.isOpened());
|
||||
}
|
||||
|
||||
TEST(AudioOpenCheck, bad_arg_invalid_audio_sample_per_second)
|
||||
{
|
||||
std::string fileName = "audio/test_audio.mp4";
|
||||
std::vector<int> params {
|
||||
CAP_PROP_AUDIO_STREAM, 0,
|
||||
CAP_PROP_VIDEO_STREAM, -1, // disabled
|
||||
CAP_PROP_AUDIO_SAMPLES_PER_SECOND, -1000
|
||||
};
|
||||
VideoCapture cap;
|
||||
cap.open(findDataFile(fileName), cv::CAP_ANY, params);
|
||||
ASSERT_FALSE(cap.isOpened());
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
@@ -0,0 +1,344 @@
|
||||
// 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.
|
||||
|
||||
// Note: all tests here are DISABLED by default due specific requirements.
|
||||
// Don't use #if 0 - these tests should be tested for compilation at least.
|
||||
//
|
||||
// Usage: opencv_test_videoio --gtest_also_run_disabled_tests --gtest_filter=*videoio_camera*<tested case>*
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
#include <opencv2/core/utils/configuration.private.hpp>
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
static void test_readFrames(/*const*/ VideoCapture& capture, const int N = 100, Mat* lastFrame = NULL, bool testTimestamps = true)
|
||||
{
|
||||
Mat frame;
|
||||
int64 time0 = cv::getTickCount();
|
||||
int64 sysTimePrev = time0;
|
||||
const double cvTickFreq = cv::getTickFrequency();
|
||||
|
||||
double camTimePrev = 0.0;
|
||||
const double fps = capture.get(cv::CAP_PROP_FPS);
|
||||
const double framePeriod = fps == 0.0 ? 1. : 1.0 / fps;
|
||||
|
||||
const bool validTickAndFps = cvTickFreq != 0 && fps != 0.;
|
||||
testTimestamps &= validTickAndFps;
|
||||
|
||||
double frame0ts = 0;
|
||||
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
SCOPED_TRACE(cv::format("frame=%d", i));
|
||||
|
||||
capture >> frame;
|
||||
ASSERT_FALSE(frame.empty());
|
||||
|
||||
const int64 sysTimeCurr = cv::getTickCount();
|
||||
double camTimeCurr = capture.get(cv::CAP_PROP_POS_MSEC);
|
||||
if (i == 0)
|
||||
frame0ts = camTimeCurr;
|
||||
camTimeCurr -= frame0ts; // normalized timestamp based on the first frame
|
||||
|
||||
if (cvtest::debugLevel > 0)
|
||||
{
|
||||
std::cout << i << ": " << camTimeCurr << std::endl;
|
||||
}
|
||||
|
||||
// Do we have a previous frame?
|
||||
if (i > 0 && testTimestamps)
|
||||
{
|
||||
const double sysTimeElapsedSecs = (sysTimeCurr - sysTimePrev) / cvTickFreq;
|
||||
const double camTimeElapsedSecs = (camTimeCurr - camTimePrev) / 1000.;
|
||||
|
||||
// Check that the time between two camera frames and two system time calls
|
||||
// are within 1.5 frame periods of one another.
|
||||
//
|
||||
// 1.5x is chosen to accommodate for a dropped frame, and an additional 50%
|
||||
// to account for drift in the scale of the camera and system time domains.
|
||||
EXPECT_NEAR(sysTimeElapsedSecs, camTimeElapsedSecs, framePeriod * 1.5);
|
||||
}
|
||||
|
||||
EXPECT_GT(cvtest::norm(frame, NORM_INF), 0) << "Complete black image has been received";
|
||||
|
||||
sysTimePrev = sysTimeCurr;
|
||||
camTimePrev = camTimeCurr;
|
||||
}
|
||||
|
||||
int64 time1 = cv::getTickCount();
|
||||
printf("Processed %d frames on %.2f FPS\n", N, (N * cvTickFreq) / (time1 - time0 + 1));
|
||||
if (lastFrame) *lastFrame = frame.clone();
|
||||
}
|
||||
|
||||
TEST(DISABLED_videoio_camera, basic)
|
||||
{
|
||||
VideoCapture capture(0);
|
||||
ASSERT_TRUE(capture.isOpened());
|
||||
std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
test_readFrames(capture);
|
||||
capture.release();
|
||||
}
|
||||
|
||||
// Test that CAP_PROP_CONVERT_RGB remain to false (default is true) after other supported property are set.
|
||||
// The test use odd value to be almost sure to trigger code responsible for recreating the device.
|
||||
TEST(DISABLED_videoio_camera, dshow_convert_rgb_persistency)
|
||||
{
|
||||
VideoCapture capture(CAP_DSHOW);
|
||||
ASSERT_TRUE(capture.isOpened());
|
||||
ASSERT_TRUE(capture.set(CAP_PROP_CONVERT_RGB, 0));
|
||||
ASSERT_DOUBLE_EQ(capture.get(CAP_PROP_CONVERT_RGB), 0);
|
||||
capture.set(CAP_PROP_FRAME_WIDTH, 641);
|
||||
capture.set(CAP_PROP_FRAME_HEIGHT, 481);
|
||||
capture.set(CAP_PROP_FPS, 31);
|
||||
capture.set(CAP_PROP_CHANNEL, 1);
|
||||
capture.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('Y', '1', '6', ' '));
|
||||
std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
ASSERT_DOUBLE_EQ(capture.get(CAP_PROP_CONVERT_RGB), 0);
|
||||
capture.release();
|
||||
}
|
||||
|
||||
TEST(DISABLED_videoio_camera, v4l_read_mjpg)
|
||||
{
|
||||
VideoCapture capture(CAP_V4L2);
|
||||
ASSERT_TRUE(capture.isOpened());
|
||||
ASSERT_TRUE(capture.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G')));
|
||||
std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
int fourcc = (int)capture.get(CAP_PROP_FOURCC);
|
||||
std::cout << "FOURCC code: " << cv::format("0x%8x", fourcc) << std::endl;
|
||||
test_readFrames(capture);
|
||||
capture.release();
|
||||
}
|
||||
|
||||
TEST(DISABLED_videoio_camera, msmf_read_yuyv)
|
||||
{
|
||||
VideoCapture capture(CAP_MSMF);
|
||||
ASSERT_TRUE(capture.isOpened());
|
||||
ASSERT_TRUE(capture.set(CAP_PROP_FOURCC, VideoWriter::fourcc('Y', 'U', 'Y', 'V')));
|
||||
std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
int fourcc = (int)capture.get(CAP_PROP_FOURCC);
|
||||
std::cout << "FOURCC code: " << cv::format("0x%8x", fourcc) << std::endl;
|
||||
cv::Mat frame;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
capture >> frame;
|
||||
EXPECT_EQ(2, frame.channels());
|
||||
}
|
||||
capture.release();
|
||||
}
|
||||
|
||||
TEST(DISABLED_videoio_camera, v4l_open_mjpg)
|
||||
{
|
||||
VideoCapture capture;
|
||||
capture.open(0, CAP_V4L2, {
|
||||
CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G')
|
||||
});
|
||||
ASSERT_TRUE(capture.isOpened());
|
||||
std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
int fourcc = (int)capture.get(CAP_PROP_FOURCC);
|
||||
std::cout << "FOURCC code: " << cv::format("0x%8x", fourcc) << std::endl;
|
||||
test_readFrames(capture);
|
||||
capture.release();
|
||||
}
|
||||
|
||||
TEST(DISABLED_videoio_camera, v4l_open_mjpg_1280x720)
|
||||
{
|
||||
VideoCapture capture(0, CAP_V4L2, {
|
||||
CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'),
|
||||
CAP_PROP_FRAME_WIDTH, 1280,
|
||||
CAP_PROP_FRAME_HEIGHT, 720,
|
||||
});
|
||||
ASSERT_TRUE(capture.isOpened());
|
||||
std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
int fourcc = (int)capture.get(CAP_PROP_FOURCC);
|
||||
std::cout << "FOURCC code: " << cv::format("0x%8x", fourcc) << std::endl;
|
||||
test_readFrames(capture);
|
||||
capture.release();
|
||||
}
|
||||
|
||||
//Following test if for capture device using PhysConn_Video_SerialDigital as crossbar input pin
|
||||
TEST(DISABLED_videoio_camera, channel6)
|
||||
{
|
||||
VideoCapture capture(0);
|
||||
ASSERT_TRUE(capture.isOpened());
|
||||
capture.set(CAP_PROP_CHANNEL, 6);
|
||||
std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
test_readFrames(capture);
|
||||
capture.release();
|
||||
}
|
||||
|
||||
TEST(DISABLED_videoio_camera, v4l_read_framesize)
|
||||
{
|
||||
VideoCapture capture(CAP_V4L2);
|
||||
ASSERT_TRUE(capture.isOpened());
|
||||
std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
int fourcc = (int)capture.get(CAP_PROP_FOURCC);
|
||||
std::cout << "FOURCC code: " << cv::format("0x%8x", fourcc) << std::endl;
|
||||
test_readFrames(capture, 30);
|
||||
|
||||
EXPECT_TRUE(capture.set(CAP_PROP_FRAME_WIDTH, 640));
|
||||
EXPECT_TRUE(capture.set(CAP_PROP_FRAME_HEIGHT, 480));
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
Mat frame640x480;
|
||||
test_readFrames(capture, 30, &frame640x480);
|
||||
EXPECT_EQ(640, frame640x480.cols);
|
||||
EXPECT_EQ(480, frame640x480.rows);
|
||||
|
||||
EXPECT_TRUE(capture.set(CAP_PROP_FRAME_WIDTH, 1280));
|
||||
EXPECT_TRUE(capture.set(CAP_PROP_FRAME_HEIGHT, 720));
|
||||
std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
|
||||
Mat frame1280x720;
|
||||
test_readFrames(capture, 30, &frame1280x720);
|
||||
EXPECT_EQ(1280, frame1280x720.cols);
|
||||
EXPECT_EQ(720, frame1280x720.rows);
|
||||
|
||||
capture.release();
|
||||
}
|
||||
|
||||
TEST(DISABLED_videoio_camera, v4l_rgb_convert)
|
||||
{
|
||||
VideoCapture capture(CAP_V4L2);
|
||||
ASSERT_TRUE(capture.isOpened());
|
||||
std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
|
||||
std::cout << " Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
|
||||
std::cout << " height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
|
||||
std::cout << "Pixel format: " << capture.get(cv::CAP_PROP_FORMAT) << std::endl;
|
||||
if (capture.get(CAP_PROP_FOURCC) != VideoWriter::fourcc('Y', 'U', 'Y', 'V'))
|
||||
{
|
||||
throw SkipTestException("Camera does not support YUYV format");
|
||||
}
|
||||
capture.set(cv::CAP_PROP_CONVERT_RGB, 0);
|
||||
std::cout << "New pixel format: " << capture.get(cv::CAP_PROP_FORMAT) << std::endl;
|
||||
|
||||
cv::Mat frame;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
int pixel_type = (int)capture.get(cv::CAP_PROP_FORMAT);
|
||||
int channels = CV_MAT_CN(pixel_type);
|
||||
int pixel_bytes = CV_ELEM_SIZE(pixel_type);
|
||||
|
||||
// YUYV is expected for most of popular USB cam (COLOR_YUV2BGR_YUYV conversion)
|
||||
EXPECT_EQ(2, channels);
|
||||
EXPECT_EQ(2, pixel_bytes);
|
||||
|
||||
capture >> frame;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
utils::Paths getTestCameras()
|
||||
{
|
||||
static utils::Paths cameras = utils::getConfigurationParameterPaths("OPENCV_TEST_CAMERA_LIST");
|
||||
return cameras;
|
||||
}
|
||||
|
||||
TEST(DISABLED_videoio_camera, waitAny_V4L)
|
||||
{
|
||||
auto cameraNames = getTestCameras();
|
||||
if (cameraNames.empty())
|
||||
throw SkipTestException("No list of tested cameras. Use OPENCV_TEST_CAMERA_LIST parameter");
|
||||
|
||||
const int totalFrames = 50; // number of expected frames (summary for all cameras)
|
||||
const int64 timeoutNS = 100 * 1000000;
|
||||
|
||||
const Size frameSize(640, 480);
|
||||
const int fpsDefaultEven = 30;
|
||||
const int fpsDefaultOdd = 15;
|
||||
|
||||
std::vector<VideoCapture> cameras;
|
||||
for (size_t i = 0; i < cameraNames.size(); ++i)
|
||||
{
|
||||
const auto& name = cameraNames[i];
|
||||
int fps = (int)utils::getConfigurationParameterSizeT(cv::format("OPENCV_TEST_CAMERA%d_FPS", (int)i).c_str(), (i & 1) ? fpsDefaultOdd : fpsDefaultEven);
|
||||
std::cout << "Camera[" << i << "] = '" << name << "', fps=" << fps << std::endl;
|
||||
VideoCapture cap(name, CAP_V4L);
|
||||
ASSERT_TRUE(cap.isOpened()) << name;
|
||||
EXPECT_TRUE(cap.set(CAP_PROP_FRAME_WIDTH, frameSize.width)) << name;
|
||||
EXPECT_TRUE(cap.set(CAP_PROP_FRAME_HEIGHT, frameSize.height)) << name;
|
||||
EXPECT_TRUE(cap.set(CAP_PROP_FPS, fps)) << name;
|
||||
//launch cameras
|
||||
Mat firstFrame;
|
||||
EXPECT_TRUE(cap.read(firstFrame));
|
||||
EXPECT_EQ(frameSize.width, firstFrame.cols);
|
||||
EXPECT_EQ(frameSize.height, firstFrame.rows);
|
||||
cameras.push_back(cap);
|
||||
}
|
||||
|
||||
std::vector<size_t> frameFromCamera(cameraNames.size(), 0);
|
||||
{
|
||||
int counter = 0;
|
||||
std::vector<int> cameraReady;
|
||||
do
|
||||
{
|
||||
EXPECT_TRUE(VideoCapture::waitAny(cameras, cameraReady, timeoutNS));
|
||||
EXPECT_FALSE(cameraReady.empty());
|
||||
for (int idx : cameraReady)
|
||||
{
|
||||
//std::cout << "Reading frame from camera: " << idx << std::endl;
|
||||
ASSERT_TRUE(idx >= 0 && (size_t)idx < cameras.size()) << idx;
|
||||
VideoCapture& c = cameras[idx];
|
||||
Mat frame;
|
||||
#if 1
|
||||
ASSERT_TRUE(c.retrieve(frame)) << idx;
|
||||
#else
|
||||
ASSERT_TRUE(c.read(frame)) << idx;
|
||||
#endif
|
||||
EXPECT_EQ(frameSize.width, frame.cols) << idx;
|
||||
EXPECT_EQ(frameSize.height, frame.rows) << idx;
|
||||
|
||||
++frameFromCamera[idx];
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
while(counter < totalFrames);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cameraNames.size(); ++i)
|
||||
{
|
||||
EXPECT_GT(frameFromCamera[i], (size_t)0) << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DISABLED_videoio_camera, ffmpeg_index)
|
||||
{
|
||||
int idx = (int)utils::getConfigurationParameterSizeT("OPENCV_TEST_FFMPEG_DEVICE_IDX", (size_t)-1);
|
||||
if (idx == -1)
|
||||
{
|
||||
throw SkipTestException("OPENCV_TEST_FFMPEG_DEVICE_IDX is not set");
|
||||
}
|
||||
VideoCapture cap;
|
||||
ASSERT_TRUE(cap.open(idx, CAP_FFMPEG));
|
||||
Mat frame;
|
||||
ASSERT_TRUE(cap.read(frame));
|
||||
ASSERT_FALSE(frame.empty());
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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"
|
||||
#include "opencv2/videoio/container_avi.private.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
TEST(videoio_builtin, basic_avi)
|
||||
{
|
||||
String filename = BunnyParameters::getFilename(".mjpg.avi");
|
||||
AVIReadContainer in;
|
||||
in.initStream(filename);
|
||||
frame_list frames;
|
||||
ASSERT_TRUE(in.parseRiff(frames));
|
||||
EXPECT_EQ(frames.size(), static_cast<unsigned>(BunnyParameters::getCount()));
|
||||
EXPECT_EQ(in.getWidth(), static_cast<unsigned>(BunnyParameters::getWidth()));
|
||||
EXPECT_EQ(in.getHeight(), static_cast<unsigned>(BunnyParameters::getHeight()));
|
||||
EXPECT_EQ(in.getFps(), static_cast<unsigned>(BunnyParameters::getFps()));
|
||||
}
|
||||
|
||||
TEST(videoio_builtin, invalid_avi)
|
||||
{
|
||||
String filename = BunnyParameters::getFilename(".avi");
|
||||
AVIReadContainer in;
|
||||
in.initStream(filename);
|
||||
frame_list frames;
|
||||
EXPECT_FALSE(in.parseRiff(frames));
|
||||
EXPECT_EQ(frames.size(), static_cast<unsigned>(0));
|
||||
}
|
||||
|
||||
TEST(videoio_builtin, read_write_avi)
|
||||
{
|
||||
const String filename = cv::tempfile("test.avi");
|
||||
const double fps = 100;
|
||||
const Size sz(800, 600);
|
||||
const size_t count = 10;
|
||||
const uchar data[count] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA};
|
||||
const Codecs codec = MJPEG;
|
||||
{
|
||||
AVIWriteContainer out;
|
||||
ASSERT_TRUE(out.initContainer(filename, fps, sz, true));
|
||||
ASSERT_TRUE(out.isOpenedStream());
|
||||
EXPECT_EQ(out.getWidth(), sz.width);
|
||||
EXPECT_EQ(out.getHeight(), sz.height);
|
||||
EXPECT_EQ(out.getChannels(), 3);
|
||||
|
||||
out.startWriteAVI(1);
|
||||
{
|
||||
out.writeStreamHeader(codec); // starts LIST chunk
|
||||
size_t chunkPointer = out.getStreamPos();
|
||||
int avi_index = out.getAVIIndex(0, dc);
|
||||
{
|
||||
out.startWriteChunk(avi_index);
|
||||
out.putStreamBytes(data, count);
|
||||
size_t tempChunkPointer = out.getStreamPos();
|
||||
size_t moviPointer = out.getMoviPointer();
|
||||
out.pushFrameOffset(chunkPointer - moviPointer);
|
||||
out.pushFrameSize(tempChunkPointer - chunkPointer - 8);
|
||||
out.endWriteChunk();
|
||||
}
|
||||
out.endWriteChunk(); // ends LIST chunk
|
||||
}
|
||||
out.writeIndex(0, dc);
|
||||
out.finishWriteAVI();
|
||||
}
|
||||
{
|
||||
AVIReadContainer in;
|
||||
in.initStream(filename);
|
||||
frame_list frames;
|
||||
ASSERT_TRUE(in.parseRiff(frames));
|
||||
EXPECT_EQ(in.getFps(), fps);
|
||||
EXPECT_EQ(in.getWidth(), static_cast<unsigned>(sz.width));
|
||||
EXPECT_EQ(in.getHeight(), static_cast<unsigned>(sz.height));
|
||||
ASSERT_EQ(frames.size(), static_cast<unsigned>(1));
|
||||
std::vector<char> actual = in.readFrame(frames.begin());
|
||||
ASSERT_EQ(actual.size(), count);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
EXPECT_EQ(actual.at(i), data[i]) << "at index " << i;
|
||||
}
|
||||
remove(filename.c_str());
|
||||
}
|
||||
|
||||
}} // opencv_test::<anonymous>::
|
||||
@@ -0,0 +1,135 @@
|
||||
// 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 {
|
||||
|
||||
const int FRAME_COUNT = 120;
|
||||
|
||||
inline void generateFrame(int i, Mat & frame)
|
||||
{
|
||||
::generateFrame(i, FRAME_COUNT, frame);
|
||||
}
|
||||
|
||||
TEST(videoio_dynamic, basic_write)
|
||||
{
|
||||
const Size FRAME_SIZE(640, 480);
|
||||
const double FPS = 100;
|
||||
const String filename = cv::tempfile(".avi");
|
||||
const int fourcc = VideoWriter::fourcc('M', 'J', 'P', 'G');
|
||||
|
||||
bool fileExists = false;
|
||||
{
|
||||
vector<VideoCaptureAPIs> backends = videoio_registry::getWriterBackends();
|
||||
for (VideoCaptureAPIs be : backends)
|
||||
{
|
||||
VideoWriter writer;
|
||||
writer.open(filename, be, fourcc, FPS, FRAME_SIZE, true);
|
||||
if (writer.isOpened())
|
||||
{
|
||||
Mat frame(FRAME_SIZE, CV_8UC3);
|
||||
for (int j = 0; j < FRAME_COUNT; ++j)
|
||||
{
|
||||
generateFrame(j, frame);
|
||||
writer << frame;
|
||||
}
|
||||
writer.release();
|
||||
fileExists = true;
|
||||
}
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
}
|
||||
}
|
||||
if (!fileExists)
|
||||
{
|
||||
cout << "None of backends has been able to write video file - SKIP reading part" << endl;
|
||||
return;
|
||||
}
|
||||
{
|
||||
vector<VideoCaptureAPIs> backends = videoio_registry::getStreamBackends();
|
||||
for (VideoCaptureAPIs be : backends)
|
||||
{
|
||||
std::string backend_name = cv::videoio_registry::getBackendName(be);
|
||||
VideoCapture cap;
|
||||
cap.open(filename, be);
|
||||
if(cap.isOpened())
|
||||
{
|
||||
int count = 0;
|
||||
while (true)
|
||||
{
|
||||
Mat frame;
|
||||
if (cap.grab())
|
||||
{
|
||||
if (cap.retrieve(frame))
|
||||
{
|
||||
++count;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (be == CAP_AVFOUNDATION)
|
||||
{
|
||||
if (FRAME_COUNT != count) // OpenCV 5.0: 5 vs 120
|
||||
throw SkipTestException(backend_name + ": invalid number of frames");
|
||||
}
|
||||
EXPECT_EQ(FRAME_COUNT, count) << backend_name;
|
||||
cap.release();
|
||||
}
|
||||
EXPECT_FALSE(cap.isOpened());
|
||||
}
|
||||
}
|
||||
remove(filename.c_str());
|
||||
}
|
||||
|
||||
TEST(videoio_dynamic, write_invalid)
|
||||
{
|
||||
vector<VideoCaptureAPIs> backends = videoio_registry::getWriterBackends();
|
||||
for (VideoCaptureAPIs be : backends)
|
||||
{
|
||||
SCOPED_TRACE(be);
|
||||
const string filename = cv::tempfile(".mkv");
|
||||
VideoWriter writer;
|
||||
bool res = true;
|
||||
|
||||
// Bad FourCC
|
||||
EXPECT_NO_THROW(res = writer.open(filename, be, VideoWriter::fourcc('A', 'B', 'C', 'D'), 1, Size(640, 480), true));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
|
||||
// Empty filename
|
||||
EXPECT_NO_THROW(res = writer.open(String(), be, VideoWriter::fourcc('H', '2', '6', '4'), 1, Size(640, 480), true));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
EXPECT_NO_THROW(res = writer.open(String(), be, VideoWriter::fourcc('M', 'J', 'P', 'G'), 1, Size(640, 480), true));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
|
||||
// zero FPS
|
||||
EXPECT_NO_THROW(res = writer.open(filename, be, VideoWriter::fourcc('H', '2', '6', '4'), 0, Size(640, 480), true));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
|
||||
// cleanup
|
||||
EXPECT_NO_THROW(writer.release());
|
||||
remove(filename.c_str());
|
||||
}
|
||||
|
||||
// Generic
|
||||
{
|
||||
VideoWriter writer;
|
||||
bool res = true;
|
||||
EXPECT_NO_THROW(res = writer.open(std::string(), VideoWriter::fourcc('H', '2', '6', '4'), 1, Size(640, 480)));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
EXPECT_NO_THROW(res = writer.open(std::string(), VideoWriter::fourcc('M', 'J', 'P', 'G'), 1, Size(640, 480)));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}} // opencv_test::<anonymous>::
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,233 @@
|
||||
// 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"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef tuple< string, Size, Size, int > Param;
|
||||
typedef testing::TestWithParam< Param > videoio_gstreamer;
|
||||
|
||||
TEST_P(videoio_gstreamer, read_check)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(CAP_GSTREAMER))
|
||||
throw SkipTestException("GStreamer backend was not found");
|
||||
|
||||
string format = get<0>(GetParam());
|
||||
Size frame_size = get<1>(GetParam());
|
||||
Size mat_size = get<2>(GetParam());
|
||||
int convertToRGB = get<3>(GetParam());
|
||||
int count_frames = 10;
|
||||
std::ostringstream pipeline;
|
||||
pipeline << "videotestsrc pattern=ball num-buffers=" << count_frames << " ! " << format;
|
||||
pipeline << ", width=" << frame_size.width << ", height=" << frame_size.height << " ! appsink";
|
||||
VideoCapture cap;
|
||||
ASSERT_NO_THROW(cap.open(pipeline.str(), CAP_GSTREAMER));
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
|
||||
EXPECT_EQ(CAP_PROP_UNKNOWN, cap.get(CV__CAP_PROP_LATEST));
|
||||
|
||||
Mat buffer, decode_frame, gray_frame, rgb_frame;
|
||||
for (int i = 0; i < count_frames; ++i)
|
||||
{
|
||||
cap >> buffer;
|
||||
decode_frame = (format == "jpegenc ! image/jpeg") ? imdecode(buffer, IMREAD_UNCHANGED) : buffer;
|
||||
EXPECT_EQ(mat_size, decode_frame.size());
|
||||
|
||||
cvtColor(decode_frame, rgb_frame, convertToRGB);
|
||||
cvtColor(rgb_frame, gray_frame, COLOR_RGB2GRAY);
|
||||
if (gray_frame.depth() == CV_16U)
|
||||
{
|
||||
gray_frame.convertTo(gray_frame, CV_8U, 255.0/65535);
|
||||
}
|
||||
|
||||
vector<Vec3f> circles;
|
||||
HoughCircles(gray_frame, circles, HOUGH_GRADIENT, 1, gray_frame.rows/16, 100, 30, 1, 30 );
|
||||
if (circles.size() == 1)
|
||||
{
|
||||
EXPECT_NEAR(18.5, circles[0][2], 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ADD_FAILURE() << "Found " << circles.size() << " on frame " << i ;
|
||||
}
|
||||
}
|
||||
{
|
||||
Mat frame;
|
||||
cap >> frame;
|
||||
EXPECT_TRUE(frame.empty());
|
||||
}
|
||||
cap.release();
|
||||
ASSERT_FALSE(cap.isOpened());
|
||||
}
|
||||
|
||||
static const Param test_data[] = {
|
||||
make_tuple("video/x-raw, format=BGR" , Size(640, 480), Size(640, 480), COLOR_BGR2RGB),
|
||||
make_tuple("video/x-raw, format=BGRA" , Size(640, 480), Size(640, 480), COLOR_BGRA2RGB),
|
||||
make_tuple("video/x-raw, format=RGBA" , Size(640, 480), Size(640, 480), COLOR_RGBA2RGB),
|
||||
make_tuple("video/x-raw, format=BGRx" , Size(640, 480), Size(640, 480), COLOR_BGRA2RGB),
|
||||
make_tuple("video/x-raw, format=RGBx" , Size(640, 480), Size(640, 480), COLOR_RGBA2RGB),
|
||||
make_tuple("video/x-raw, format=GRAY8", Size(640, 480), Size(640, 480), COLOR_GRAY2RGB),
|
||||
make_tuple("video/x-raw, format=UYVY" , Size(640, 480), Size(640, 480), COLOR_YUV2RGB_UYVY),
|
||||
make_tuple("video/x-raw, format=YUY2" , Size(640, 480), Size(640, 480), COLOR_YUV2RGB_YUY2),
|
||||
make_tuple("video/x-raw, format=YVYU" , Size(640, 480), Size(640, 480), COLOR_YUV2RGB_YVYU),
|
||||
make_tuple("video/x-raw, format=NV12" , Size(640, 480), Size(640, 720), COLOR_YUV2RGB_NV12),
|
||||
make_tuple("video/x-raw, format=NV21" , Size(640, 480), Size(640, 720), COLOR_YUV2RGB_NV21),
|
||||
make_tuple("video/x-raw, format=YV12" , Size(640, 480), Size(640, 720), COLOR_YUV2RGB_YV12),
|
||||
make_tuple("video/x-raw, format=I420" , Size(640, 480), Size(640, 720), COLOR_YUV2RGB_I420),
|
||||
make_tuple("video/x-bayer" , Size(640, 480), Size(640, 480), COLOR_BayerBG2RGB),
|
||||
make_tuple("jpegenc ! image/jpeg" , Size(640, 480), Size(640, 480), COLOR_BGR2RGB),
|
||||
|
||||
// unaligned cases, strides information must be used
|
||||
make_tuple("video/x-raw, format=BGR" , Size(322, 242), Size(322, 242), COLOR_BGR2RGB),
|
||||
make_tuple("video/x-raw, format=GRAY8", Size(322, 242), Size(322, 242), COLOR_GRAY2RGB),
|
||||
make_tuple("video/x-raw, format=NV12" , Size(322, 242), Size(322, 363), COLOR_YUV2RGB_NV12),
|
||||
make_tuple("video/x-raw, format=NV21" , Size(322, 242), Size(322, 363), COLOR_YUV2RGB_NV21),
|
||||
make_tuple("video/x-raw, format=YV12" , Size(322, 242), Size(322, 363), COLOR_YUV2RGB_YV12),
|
||||
make_tuple("video/x-raw, format=I420" , Size(322, 242), Size(322, 363), COLOR_YUV2RGB_I420),
|
||||
|
||||
// 16 bit
|
||||
make_tuple("video/x-raw, format=GRAY16_LE", Size(640, 480), Size(640, 480), COLOR_GRAY2RGB),
|
||||
make_tuple("video/x-raw, format=GRAY16_BE", Size(640, 480), Size(640, 480), COLOR_GRAY2RGB),
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(videoio, videoio_gstreamer, testing::ValuesIn(test_data));
|
||||
|
||||
TEST(videoio_gstreamer, unsupported_pipeline)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(CAP_GSTREAMER))
|
||||
throw SkipTestException("GStreamer backend was not found");
|
||||
|
||||
// could not link videoconvert0 to matroskamux0, matroskamux0 can't handle caps video/x-raw, format=(string)RGBA
|
||||
std::string pipeline = "appsrc ! videoconvert ! video/x-raw, format=(string)RGBA ! matroskamux ! filesink location=test.mkv";
|
||||
Size frame_size(640, 480);
|
||||
|
||||
VideoWriter writer;
|
||||
EXPECT_NO_THROW(writer.open(pipeline, CAP_GSTREAMER, 0/*fourcc*/, 30/*fps*/, frame_size, true));
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
// no frames
|
||||
EXPECT_NO_THROW(writer.release());
|
||||
|
||||
}
|
||||
|
||||
TEST(videoio_gstreamer, gray16_writing)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(CAP_GSTREAMER))
|
||||
throw SkipTestException("GStreamer backend was not found");
|
||||
|
||||
Size frame_size(320, 240);
|
||||
|
||||
// generate a noise frame
|
||||
Mat frame = Mat(frame_size, CV_16U);
|
||||
randu(frame, 0, 65535);
|
||||
|
||||
// generate a temp filename, and fix path separators to how GStreamer expects them
|
||||
cv::String temp_file = cv::tempfile(".raw");
|
||||
std::replace(temp_file.begin(), temp_file.end(), '\\', '/');
|
||||
|
||||
// write noise frame to file using GStreamer
|
||||
std::ostringstream writer_pipeline;
|
||||
writer_pipeline << "appsrc ! filesink location=" << temp_file;
|
||||
std::vector<int> params {
|
||||
VIDEOWRITER_PROP_IS_COLOR, 0/*false*/,
|
||||
VIDEOWRITER_PROP_DEPTH, CV_16U
|
||||
};
|
||||
VideoWriter writer;
|
||||
ASSERT_NO_THROW(writer.open(writer_pipeline.str(), CAP_GSTREAMER, 0/*fourcc*/, 30/*fps*/, frame_size, params));
|
||||
ASSERT_TRUE(writer.isOpened());
|
||||
ASSERT_NO_THROW(writer.write(frame));
|
||||
ASSERT_NO_THROW(writer.release());
|
||||
|
||||
// read noise frame back in
|
||||
Mat written_frame(frame_size, CV_16U);
|
||||
std::ifstream fs(temp_file, std::ios::in | std::ios::binary);
|
||||
fs.read((char*)written_frame.ptr(0), frame_size.width * frame_size.height * 2);
|
||||
ASSERT_TRUE(fs);
|
||||
fs.close();
|
||||
|
||||
// compare to make sure it's identical
|
||||
EXPECT_EQ(0, cv::norm(frame, written_frame, NORM_INF));
|
||||
|
||||
// remove temp file
|
||||
EXPECT_EQ(0, remove(temp_file.c_str()));
|
||||
}
|
||||
|
||||
TEST(videoio_gstreamer, timeout_property)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(CAP_GSTREAMER))
|
||||
throw SkipTestException("GStreamer backend was not found");
|
||||
|
||||
VideoCapture cap;
|
||||
cap.open("videotestsrc ! appsink", CAP_GSTREAMER);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
const double default_timeout = 30000; // 30 seconds
|
||||
const double open_timeout = 5678; // 3 seconds
|
||||
const double read_timeout = 1234; // 1 second
|
||||
EXPECT_NEAR(default_timeout, cap.get(CAP_PROP_OPEN_TIMEOUT_MSEC), 1e-3);
|
||||
const double current_read_timeout = cap.get(CAP_PROP_READ_TIMEOUT_MSEC);
|
||||
const bool read_timeout_supported = current_read_timeout > 0.0;
|
||||
if (read_timeout_supported)
|
||||
{
|
||||
EXPECT_NEAR(default_timeout, current_read_timeout, 1e-3);
|
||||
}
|
||||
cap.set(CAP_PROP_OPEN_TIMEOUT_MSEC, open_timeout);
|
||||
EXPECT_NEAR(open_timeout, cap.get(CAP_PROP_OPEN_TIMEOUT_MSEC), 1e-3);
|
||||
if (read_timeout_supported)
|
||||
{
|
||||
cap.set(CAP_PROP_READ_TIMEOUT_MSEC, read_timeout);
|
||||
EXPECT_NEAR(read_timeout, cap.get(CAP_PROP_READ_TIMEOUT_MSEC), 1e-3);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Seeking test with manual GStreamer pipeline
|
||||
typedef testing::TestWithParam<string> gstreamer_bunny;
|
||||
|
||||
TEST_P(gstreamer_bunny, manual_seek)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(CAP_GSTREAMER))
|
||||
throw SkipTestException("GStreamer backend was not found");
|
||||
|
||||
const string video_file = BunnyParameters::getFilename("." + GetParam());
|
||||
const string pipeline = "filesrc location=" + video_file + " ! decodebin ! videoconvert ! video/x-raw, format=BGR ! appsink drop=1";
|
||||
const double target_pos = 3000.0;
|
||||
const double ms_per_frame = 1000.0 / BunnyParameters::getFps();
|
||||
VideoCapture cap;
|
||||
cap.open(pipeline, CAP_GSTREAMER);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
Mat img;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
cap >> img;
|
||||
}
|
||||
EXPECT_FALSE(img.empty());
|
||||
cap.set(CAP_PROP_POS_MSEC, target_pos);
|
||||
cap >> img;
|
||||
EXPECT_FALSE(img.empty());
|
||||
double actual_pos = cap.get(CAP_PROP_POS_MSEC);
|
||||
EXPECT_NEAR(actual_pos, target_pos, ms_per_frame);
|
||||
}
|
||||
|
||||
static const string bunny_params[] = {
|
||||
// string("wmv"),
|
||||
string("mov"),
|
||||
string("mp4"),
|
||||
// string("mpg"),
|
||||
string("avi"),
|
||||
// string("h264"),
|
||||
// string("h265"),
|
||||
string("mjpg.avi")
|
||||
};
|
||||
|
||||
inline static std::string gstreamer_bunny_name_printer(const testing::TestParamInfo<gstreamer_bunny::ParamType>& info)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << extToStringSafe(info.param);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(videoio, gstreamer_bunny, testing::ValuesIn(bunny_params), gstreamer_bunny_name_printer);
|
||||
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,376 @@
|
||||
// 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"
|
||||
#include "opencv2/core/utils/filesystem.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/videoio/utils.private.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
struct ImageCollection
|
||||
{
|
||||
string dirname;
|
||||
string base;
|
||||
string ext;
|
||||
size_t first_idx;
|
||||
size_t last_idx;
|
||||
size_t width;
|
||||
public:
|
||||
ImageCollection(const char *dirname_template = "opencv_test_images")
|
||||
: first_idx(0), last_idx(0), width(0)
|
||||
{
|
||||
dirname = cv::tempfile(dirname_template);
|
||||
cv::utils::fs::createDirectory(dirname);
|
||||
}
|
||||
~ImageCollection()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
void cleanup()
|
||||
{
|
||||
cv::utils::fs::remove_all(dirname);
|
||||
}
|
||||
void generate(size_t count, size_t first = 0, size_t width_ = 4, const string & base_ = "test", const string & ext_ = "png")
|
||||
{
|
||||
base = base_;
|
||||
ext = ext_;
|
||||
first_idx = first;
|
||||
last_idx = first + count - 1;
|
||||
width = width_;
|
||||
for (size_t idx = first_idx; idx <= last_idx; ++idx)
|
||||
{
|
||||
const string filename = getFilename(idx);
|
||||
imwrite(filename, getFrame(idx));
|
||||
}
|
||||
}
|
||||
string getFilename(size_t idx = 0) const
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << dirname << "/" << base << setw(width) << setfill('0') << idx << "." << ext;
|
||||
return buf.str();
|
||||
}
|
||||
string getPatternFilename() const
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << dirname << "/" << base << "%0" << width << "d" << "." << ext;
|
||||
return buf.str();
|
||||
}
|
||||
string getFirstFilename() const
|
||||
{
|
||||
return getFilename(first_idx);
|
||||
}
|
||||
Mat getFirstFrame() const
|
||||
{
|
||||
return getFrame(first_idx);
|
||||
}
|
||||
size_t getCount() const
|
||||
{
|
||||
return last_idx - first_idx + 1;
|
||||
}
|
||||
string getDirname() const
|
||||
{
|
||||
return dirname;
|
||||
}
|
||||
static Mat getFrame(size_t idx)
|
||||
{
|
||||
const int sz = 100; // 100x100 or bigger
|
||||
Mat res(sz, sz, CV_8UC3, Scalar::all(0));
|
||||
circle(res, Point(idx % 100), idx % 50, Scalar::all(255), 2, LINE_8);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
TEST(videoio_images, basic_read)
|
||||
{
|
||||
ImageCollection col;
|
||||
col.generate(20);
|
||||
VideoCapture cap(col.getFirstFilename(), CAP_IMAGES);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
size_t idx = 0;
|
||||
while (cap.isOpened()) // TODO: isOpened is always true, even if there are no more images
|
||||
{
|
||||
Mat img;
|
||||
const bool read_res = cap.read(img);
|
||||
if (!read_res)
|
||||
break;
|
||||
EXPECT_MAT_N_DIFF(img, col.getFrame(idx), 0);
|
||||
++idx;
|
||||
}
|
||||
EXPECT_EQ(col.getCount(), idx);
|
||||
}
|
||||
|
||||
TEST(videoio_images, basic_write)
|
||||
{
|
||||
// writer should create files: test0000.png, ... test0019.png
|
||||
ImageCollection col;
|
||||
col.generate(1);
|
||||
VideoWriter wri(col.getFirstFilename(), CAP_IMAGES, 0, 0, col.getFrame(0).size());
|
||||
ASSERT_TRUE(wri.isOpened());
|
||||
size_t idx = 0;
|
||||
while (wri.isOpened())
|
||||
{
|
||||
wri << col.getFrame(idx);
|
||||
Mat actual = imread(col.getFilename(idx));
|
||||
EXPECT_MAT_N_DIFF(col.getFrame(idx), actual, 0);
|
||||
if (++idx >= 20)
|
||||
break;
|
||||
}
|
||||
wri.release();
|
||||
ASSERT_FALSE(wri.isOpened());
|
||||
}
|
||||
|
||||
TEST(videoio_images, bad)
|
||||
{
|
||||
ImageCollection col;
|
||||
{
|
||||
ostringstream buf; buf << col.getDirname() << "/missing0000.png";
|
||||
VideoCapture cap(buf.str(), CAP_IMAGES);
|
||||
EXPECT_FALSE(cap.isOpened());
|
||||
Mat img;
|
||||
EXPECT_FALSE(cap.read(img));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(videoio_images, write_returns_status)
|
||||
{
|
||||
ImageCollection col;
|
||||
col.generate(1);
|
||||
VideoWriter wri(col.getFirstFilename(), CAP_IMAGES, 0, 0, col.getFrame(0).size());
|
||||
ASSERT_TRUE(wri.isOpened());
|
||||
EXPECT_EQ(CAP_PROP_UNKNOWN, wri.get(CV__CAP_PROP_LATEST));
|
||||
|
||||
const Mat frame = col.getFrame(0);
|
||||
|
||||
EXPECT_TRUE(wri.write(frame));
|
||||
wri.release();
|
||||
ASSERT_FALSE(wri.isOpened());
|
||||
EXPECT_FALSE(wri.write(frame));
|
||||
|
||||
VideoWriter empty;
|
||||
EXPECT_FALSE(empty.isOpened());
|
||||
EXPECT_FALSE(empty.write(frame));
|
||||
}
|
||||
|
||||
TEST(videoio_images, seek)
|
||||
{
|
||||
// check files: test0005.png, ..., test0024.png
|
||||
// seek to valid and invalid frame numbers
|
||||
// position is zero-based: valid frame numbers are 0, ..., 19
|
||||
const int count = 20;
|
||||
ImageCollection col;
|
||||
col.generate(count, 5);
|
||||
VideoCapture cap(col.getFirstFilename(), CAP_IMAGES);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
EXPECT_EQ((size_t)count, (size_t)cap.get(CAP_PROP_FRAME_COUNT));
|
||||
vector<int> positions { count / 2, 0, 1, count - 1, count, count + 100, -1, -100 };
|
||||
for (const auto &pos : positions)
|
||||
{
|
||||
Mat img;
|
||||
const bool res = cap.set(CAP_PROP_POS_FRAMES, pos);
|
||||
if (pos >= count || pos < 0) // invalid position
|
||||
{
|
||||
// EXPECT_FALSE(res); // TODO: backend clamps invalid value to valid range, actual result is 'true'
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_TRUE(res);
|
||||
EXPECT_GE(1., cap.get(CAP_PROP_POS_AVI_RATIO));
|
||||
EXPECT_NEAR((double)pos / (count - 1), cap.get(CAP_PROP_POS_AVI_RATIO), 1e-2);
|
||||
EXPECT_EQ(pos, static_cast<decltype(pos)>(cap.get(CAP_PROP_POS_FRAMES)));
|
||||
EXPECT_TRUE(cap.read(img));
|
||||
EXPECT_MAT_N_DIFF(img, col.getFrame(col.first_idx + pos), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(videoio_images, pattern_overflow)
|
||||
{
|
||||
// check files: test0.png, ..., test11.png
|
||||
ImageCollection col;
|
||||
col.generate(12, 0, 1);
|
||||
|
||||
{
|
||||
VideoCapture cap(col.getFirstFilename(), CAP_IMAGES);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
for (size_t idx = col.first_idx; idx <= col.last_idx; ++idx)
|
||||
{
|
||||
Mat img;
|
||||
EXPECT_TRUE(cap.read(img));
|
||||
EXPECT_MAT_N_DIFF(img, col.getFrame(idx), 0);
|
||||
}
|
||||
}
|
||||
{
|
||||
VideoCapture cap(col.getPatternFilename(), CAP_IMAGES);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
for (size_t idx = col.first_idx; idx <= col.last_idx; ++idx)
|
||||
{
|
||||
Mat img;
|
||||
EXPECT_TRUE(cap.read(img));
|
||||
EXPECT_MAT_N_DIFF(img, col.getFrame(idx), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(videoio_images, pattern_max)
|
||||
{
|
||||
// max supported number width for starting image is 9 digits
|
||||
// but following images can be read as well
|
||||
// test999999999.png ; test1000000000.png
|
||||
ImageCollection col;
|
||||
col.generate(2, 1000000000 - 1);
|
||||
{
|
||||
VideoCapture cap(col.getFirstFilename(), CAP_IMAGES);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
Mat img;
|
||||
EXPECT_TRUE(cap.read(img));
|
||||
EXPECT_MAT_N_DIFF(img, col.getFrame(col.first_idx), 0);
|
||||
EXPECT_TRUE(cap.read(img));
|
||||
EXPECT_MAT_N_DIFF(img, col.getFrame(col.first_idx + 1), 0);
|
||||
}
|
||||
{
|
||||
VideoWriter wri(col.getFirstFilename(), CAP_IMAGES, 0, 0, col.getFirstFrame().size());
|
||||
ASSERT_TRUE(wri.isOpened());
|
||||
Mat img = col.getFrame(0);
|
||||
wri.write(img);
|
||||
wri.write(img);
|
||||
Mat actual;
|
||||
actual = imread(col.getFilename(col.first_idx));
|
||||
EXPECT_MAT_N_DIFF(actual, img, 0);
|
||||
actual = imread(col.getFilename(col.first_idx));
|
||||
EXPECT_MAT_N_DIFF(actual, img, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(videoio_images, extract_pattern)
|
||||
{
|
||||
unsigned offset = 0;
|
||||
|
||||
// Min and max values
|
||||
EXPECT_EQ("%01d.png", cv::icvExtractPattern("0.png", &offset));
|
||||
EXPECT_EQ(0u, offset);
|
||||
EXPECT_EQ("%09d.png", cv::icvExtractPattern("999999999.png", &offset));
|
||||
EXPECT_EQ(999999999u, offset);
|
||||
|
||||
// Regular usage - start, end, middle
|
||||
EXPECT_EQ("abc%04ddef.png", cv::icvExtractPattern("abc0048def.png", &offset));
|
||||
EXPECT_EQ(48u, offset);
|
||||
EXPECT_EQ("%05dabcdef.png", cv::icvExtractPattern("00049abcdef.png", &offset));
|
||||
EXPECT_EQ(49u, offset);
|
||||
EXPECT_EQ("abcdef%06d.png", cv::icvExtractPattern("abcdef000050.png", &offset));
|
||||
EXPECT_EQ(50u, offset);
|
||||
|
||||
// Minus handling (should not handle)
|
||||
EXPECT_EQ("abcdef-%01d.png", cv::icvExtractPattern("abcdef-8.png", &offset));
|
||||
EXPECT_EQ(8u, offset);
|
||||
|
||||
// Two numbers (should select first)
|
||||
// TODO: shouldn't it be last number?
|
||||
EXPECT_EQ("%01d-abcdef-8.png", cv::icvExtractPattern("7-abcdef-8.png", &offset));
|
||||
EXPECT_EQ(7u, offset);
|
||||
|
||||
// Paths (should select filename)
|
||||
EXPECT_EQ("images005/abcdef%03d.png", cv::icvExtractPattern("images005/abcdef006.png", &offset));
|
||||
EXPECT_EQ(6u, offset);
|
||||
// TODO: fix
|
||||
// EXPECT_EQ("images03\\abcdef%02d.png", cv::icvExtractPattern("images03\\abcdef04.png", &offset));
|
||||
// EXPECT_EQ(4, offset);
|
||||
EXPECT_EQ("/home/user/test/0/3348/../../3442/./0/1/3/4/5/14304324234/%01d.png",
|
||||
cv::icvExtractPattern("/home/user/test/0/3348/../../3442/./0/1/3/4/5/14304324234/2.png", &offset));
|
||||
EXPECT_EQ(2u, offset);
|
||||
|
||||
// Patterns '%0?[0-9][du]'
|
||||
EXPECT_EQ("test%d.png", cv::icvExtractPattern("test%d.png", &offset));
|
||||
EXPECT_EQ(0u, offset);
|
||||
EXPECT_EQ("test%0d.png", cv::icvExtractPattern("test%0d.png", &offset));
|
||||
EXPECT_EQ(0u, offset);
|
||||
EXPECT_EQ("test%09d.png", cv::icvExtractPattern("test%09d.png", &offset));
|
||||
EXPECT_EQ(0u, offset);
|
||||
EXPECT_EQ("test%5u.png", cv::icvExtractPattern("test%5u.png", &offset));
|
||||
EXPECT_EQ(0u, offset);
|
||||
|
||||
// Invalid arguments
|
||||
EXPECT_THROW(cv::icvExtractPattern(string(), &offset), cv::Exception);
|
||||
// TODO: fix?
|
||||
// EXPECT_EQ(0u, offset);
|
||||
EXPECT_THROW(cv::icvExtractPattern("test%010d.png", &offset), cv::Exception);
|
||||
EXPECT_EQ(0u, offset);
|
||||
EXPECT_THROW(cv::icvExtractPattern("1000000000.png", &offset), cv::Exception);
|
||||
EXPECT_EQ(0u, offset);
|
||||
EXPECT_THROW(cv::icvExtractPattern("1.png", NULL), cv::Exception);
|
||||
}
|
||||
|
||||
TEST(videoio_images, bug_26457)
|
||||
{
|
||||
ImageCollection col;
|
||||
col.generate(1u);
|
||||
ASSERT_EQ(col.getCount(), 1u);
|
||||
|
||||
VideoCapture cap(col.getFirstFilename(), CAP_IMAGES);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
|
||||
Mat img;
|
||||
const bool read_res = cap.read(img);
|
||||
EXPECT_TRUE(read_res);
|
||||
EXPECT_MAT_N_DIFF(img, col.getFirstFrame(), 0);
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<VideoCaptureAPIs> videoio_image_seq_start;
|
||||
|
||||
TEST_P(videoio_image_seq_start, open)
|
||||
{
|
||||
const VideoCaptureAPIs apiPref = GetParam();
|
||||
if (!videoio_registry::hasBackend(apiPref))
|
||||
throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
|
||||
|
||||
// Sequence starts at an index outside the auto-probe range
|
||||
// Opening with only the pattern must fail without the property, and succeed when it is set
|
||||
const int start = 100;
|
||||
const size_t count = 5;
|
||||
ImageCollection col;
|
||||
col.generate(count, start);
|
||||
const std::string pattern = col.getPatternFilename();
|
||||
|
||||
{
|
||||
VideoCapture cap(pattern, apiPref);
|
||||
EXPECT_FALSE(cap.isOpened());
|
||||
}
|
||||
|
||||
{
|
||||
VideoCapture cap;
|
||||
ASSERT_TRUE(cap.open(pattern, apiPref,
|
||||
{ CAP_PROP_IMAGE_SEQ_START, start }));
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
EXPECT_EQ(CAP_PROP_UNKNOWN, cap.get(CV__CAP_PROP_LATEST));
|
||||
for (size_t idx = 0; idx < count; ++idx)
|
||||
{
|
||||
Mat img;
|
||||
ASSERT_TRUE(cap.read(img));
|
||||
EXPECT_MAT_N_DIFF(img, col.getFrame(start + idx), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PR: https://github.com/opencv/opencv/pull/28844/
|
||||
// Requires FFmpeg wrapper re-build on Windows
|
||||
static const VideoCaptureAPIs BackendsWithSeqStart[] =
|
||||
{
|
||||
CAP_IMAGES
|
||||
#ifndef _WIN32
|
||||
,CAP_FFMPEG
|
||||
#endif
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(videoio_images, videoio_image_seq_start, testing::ValuesIn(BackendsWithSeqStart));
|
||||
|
||||
// TODO: should writer overwrite files?
|
||||
// TODO: is clamping good for seeking?
|
||||
// TODO: missing files? E.g. 3, 4, 6, 7, 8 (should it finish OR jump over OR return empty frame?)
|
||||
// TODO: non-numbered files (https://github.com/opencv/opencv/pull/23815)
|
||||
|
||||
}} // opencv_test::<anonymous>::
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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"
|
||||
#include <opencv2/core/utils/logger.hpp>
|
||||
|
||||
#if defined(HAVE_HPX)
|
||||
#include <hpx/hpx_main.hpp>
|
||||
#endif
|
||||
|
||||
static
|
||||
void initTests()
|
||||
{
|
||||
const std::vector<cv::VideoCaptureAPIs> backends = cv::videoio_registry::getStreamBackends();
|
||||
bool requireFFmpeg = cv::utils::getConfigurationParameterBool("OPENCV_TEST_VIDEOIO_BACKEND_REQUIRE_FFMPEG");
|
||||
if (requireFFmpeg && !isBackendAvailable(cv::CAP_FFMPEG, backends))
|
||||
{
|
||||
CV_LOG_FATAL(NULL, "OpenCV-Test: required FFmpeg backend is not available (broken plugin?). STOP.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
CV_TEST_MAIN("highgui", initTests())
|
||||
@@ -0,0 +1,176 @@
|
||||
// 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"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
TEST(videoio_mfx, read_invalid)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(CAP_INTEL_MFX))
|
||||
throw SkipTestException("MediaSDK backend was not found");
|
||||
|
||||
VideoCapture cap;
|
||||
ASSERT_NO_THROW(cap.open("nonexistent-file", CAP_INTEL_MFX));
|
||||
ASSERT_FALSE(cap.isOpened());
|
||||
Mat img;
|
||||
ASSERT_NO_THROW(cap >> img);
|
||||
ASSERT_TRUE(img.empty());
|
||||
}
|
||||
|
||||
TEST(videoio_mfx, write_invalid)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(CAP_INTEL_MFX))
|
||||
throw SkipTestException("MediaSDK backend was not found");
|
||||
|
||||
const string filename = cv::tempfile(".264");
|
||||
VideoWriter writer;
|
||||
bool res = true;
|
||||
ASSERT_NO_THROW(res = writer.open(filename, CAP_INTEL_MFX, VideoWriter::fourcc('H', '2', '6', '4'), 1, Size(641, 480), true));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
ASSERT_NO_THROW(res = writer.open(filename, CAP_INTEL_MFX, VideoWriter::fourcc('H', '2', '6', '4'), 1, Size(640, 481), true));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
ASSERT_NO_THROW(res = writer.open(filename, CAP_INTEL_MFX, VideoWriter::fourcc('A', 'B', 'C', 'D'), 1, Size(640, 480), true));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
ASSERT_NO_THROW(res = writer.open(String(), CAP_INTEL_MFX, VideoWriter::fourcc('H', '2', '6', '4'), 1, Size(640, 480), true));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
ASSERT_NO_THROW(res = writer.open(filename, CAP_INTEL_MFX, VideoWriter::fourcc('H', '2', '6', '4'), 0, Size(640, 480), true));
|
||||
EXPECT_FALSE(res);
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
|
||||
ASSERT_NO_THROW(res = writer.open(filename, CAP_INTEL_MFX, VideoWriter::fourcc('H', '2', '6', '4'), 30, Size(640, 480), true));
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_TRUE(writer.isOpened());
|
||||
Mat t;
|
||||
// write some bad frames
|
||||
t = Mat(Size(1024, 768), CV_8UC3);
|
||||
EXPECT_NO_THROW(writer << t);
|
||||
t = Mat(Size(320, 240), CV_8UC3);
|
||||
EXPECT_NO_THROW(writer << t);
|
||||
t = Mat(Size(640, 480), CV_8UC2);
|
||||
EXPECT_NO_THROW(writer << t);
|
||||
|
||||
// cleanup
|
||||
ASSERT_NO_THROW(writer.release());
|
||||
remove(filename.c_str());
|
||||
}
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
const int FRAME_COUNT = 20;
|
||||
|
||||
inline void generateFrame(int i, Mat & frame)
|
||||
{
|
||||
::generateFrame(i, FRAME_COUNT, frame);
|
||||
}
|
||||
|
||||
inline int fourccByExt(const String &ext)
|
||||
{
|
||||
if (ext == ".mpeg2")
|
||||
return VideoWriter::fourcc('M', 'P', 'G', '2');
|
||||
else if (ext == ".264")
|
||||
return VideoWriter::fourcc('H', '2', '6', '4');
|
||||
else if (ext == ".265")
|
||||
return VideoWriter::fourcc('H', '2', '6', '5');
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
typedef tuple<Size, double, const char *> Size_FPS_Ext;
|
||||
typedef testing::TestWithParam< Size_FPS_Ext > videoio_mfx;
|
||||
|
||||
TEST_P(videoio_mfx, read_write_raw)
|
||||
{
|
||||
if (!videoio_registry::hasBackend(CAP_INTEL_MFX))
|
||||
throw SkipTestException("MediaSDK backend was not found");
|
||||
|
||||
const Size FRAME_SIZE = get<0>(GetParam());
|
||||
const double FPS = get<1>(GetParam());
|
||||
const char *ext = get<2>(GetParam());
|
||||
const String filename = cv::tempfile(ext);
|
||||
const int fourcc = fourccByExt(ext);
|
||||
|
||||
// For some reason MPEG2 codec does not work well with this particular videostream at 1 FPS
|
||||
// even with large bitrate values. Thus skipping this case.
|
||||
if (FPS == 1. && fourcc == VideoWriter::fourcc('M', 'P', 'G', '2'))
|
||||
throw SkipTestException("This configuration is not supported");
|
||||
|
||||
bool isColor = true;
|
||||
std::queue<Mat> goodFrames;
|
||||
|
||||
// Write video
|
||||
VideoWriter writer;
|
||||
writer.open(filename, CAP_INTEL_MFX, fourcc, FPS, FRAME_SIZE, isColor);
|
||||
ASSERT_TRUE(writer.isOpened());
|
||||
Mat frame(FRAME_SIZE, CV_8UC3);
|
||||
for (int i = 0; i < FRAME_COUNT; ++i)
|
||||
{
|
||||
generateFrame(i, frame);
|
||||
goodFrames.push(frame.clone());
|
||||
writer << frame;
|
||||
}
|
||||
writer.release();
|
||||
EXPECT_FALSE(writer.isOpened());
|
||||
|
||||
// Read video
|
||||
VideoCapture cap;
|
||||
cap.open(filename, CAP_INTEL_MFX);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
EXPECT_EQ(FRAME_SIZE.width, cap.get(CAP_PROP_FRAME_WIDTH));
|
||||
EXPECT_EQ(FRAME_SIZE.height, cap.get(CAP_PROP_FRAME_HEIGHT));
|
||||
double psnrThreshold = (fourcc == VideoWriter::fourcc('M', 'P', 'G', '2')) ? 27.0 : 29.5; // experimentally chosen value
|
||||
for (int i = 0; i < FRAME_COUNT; ++i)
|
||||
{
|
||||
SCOPED_TRACE(i);
|
||||
ASSERT_TRUE(cap.read(frame));
|
||||
ASSERT_FALSE(frame.empty());
|
||||
ASSERT_EQ(FRAME_SIZE.width, frame.cols);
|
||||
ASSERT_EQ(FRAME_SIZE.height, frame.rows);
|
||||
// verify
|
||||
ASSERT_NE(goodFrames.size(), 0u);
|
||||
const Mat goodFrame = goodFrames.front(); goodFrames.pop();
|
||||
EXPECT_EQ(goodFrame.depth(), frame.depth());
|
||||
EXPECT_EQ(goodFrame.channels(), frame.channels());
|
||||
EXPECT_EQ(goodFrame.type(), frame.type());
|
||||
double psnr = cvtest::PSNR(goodFrame, frame);
|
||||
if ((i == 1 || i == 4) && fourcc == VideoWriter::fourcc('H', '2', '6', '5'))
|
||||
{
|
||||
// ignore bugs of some HW/SW configurations:
|
||||
// - (added 2021-10) i7-11700K, Win10, oneVPL 2021.4.0 / 2021.6.0
|
||||
std::cout << "SKIP: bypass frame content check: i=" << i << " psnr=" << psnr << ", expected to be >= " << psnrThreshold << std::endl;
|
||||
continue;
|
||||
}
|
||||
EXPECT_GE(psnr, psnrThreshold);
|
||||
}
|
||||
EXPECT_FALSE(cap.read(frame));
|
||||
EXPECT_TRUE(frame.empty());
|
||||
cap.release();
|
||||
EXPECT_FALSE(cap.isOpened());
|
||||
remove(filename.c_str());
|
||||
}
|
||||
|
||||
inline static std::string videoio_mfx_name_printer(const testing::TestParamInfo<videoio_mfx::ParamType>& info)
|
||||
{
|
||||
std::ostringstream out;
|
||||
const Size sz = get<0>(info.param);
|
||||
out << sz.height << "p" << "_"
|
||||
<< get<1>(info.param) << "FPS" << "_"
|
||||
<< extToStringSafe(get<2>(info.param));
|
||||
return out.str();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(videoio, videoio_mfx,
|
||||
testing::Combine(
|
||||
testing::Values(Size(640, 480), Size(638, 478), Size(636, 476), Size(1920, 1080)),
|
||||
testing::Values(1, 30, 100),
|
||||
testing::Values(".mpeg2", ".264", ".265")),
|
||||
videoio_mfx_name_printer);
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,41 @@
|
||||
// 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.
|
||||
// Usage: opencv_test_videoio --gtest_also_run_disabled_tests
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
TEST(DISABLED_videoio_micro, basic)
|
||||
{
|
||||
int cursize = 0;
|
||||
int validSize = 0;
|
||||
Mat frame;
|
||||
|
||||
std::vector<int> params { CAP_PROP_AUDIO_STREAM, 0, CAP_PROP_VIDEO_STREAM, -1 };
|
||||
VideoCapture cap(0, cv::CAP_MSMF, params);
|
||||
ASSERT_TRUE(cap.isOpened());
|
||||
|
||||
int samplesPerSecond = (int)cap.get(cv::CAP_PROP_AUDIO_SAMPLES_PER_SECOND);
|
||||
const int audio_base_index = (int)cap.get(cv::CAP_PROP_AUDIO_BASE_INDEX);
|
||||
|
||||
const double cvTickFreq = cv::getTickFrequency();
|
||||
int64 sysTimePrev = cv::getTickCount();
|
||||
int64 sysTimeCurr = cv::getTickCount();
|
||||
|
||||
cout << "Audio would be captured for the next 10 seconds" << endl;
|
||||
while ((sysTimeCurr-sysTimePrev)/cvTickFreq < 10)
|
||||
{
|
||||
if (cap.grab())
|
||||
{
|
||||
ASSERT_TRUE(cap.retrieve(frame, audio_base_index));
|
||||
sysTimeCurr = cv::getTickCount();
|
||||
}
|
||||
}
|
||||
validSize = samplesPerSecond*(int)((sysTimeCurr-sysTimePrev)/cvTickFreq);
|
||||
cursize = (int)cap.get(cv::CAP_PROP_AUDIO_POS);
|
||||
ASSERT_LT(validSize - cursize, cursize*0.05);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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 {
|
||||
|
||||
struct VideoCaptureAPITests: TestWithParam<cv::VideoCaptureAPIs>
|
||||
{
|
||||
void SetUp()
|
||||
{
|
||||
cv::VideoCaptureAPIs api = GetParam();
|
||||
if (!videoio_registry::hasBackend(api))
|
||||
throw SkipTestException("backend " + std::to_string(int(api)) + " was not found");
|
||||
|
||||
string video_file = string(cvtest::TS::ptr()->get_data_path()) + "video/rotated_metadata.mp4";
|
||||
|
||||
EXPECT_NO_THROW(cap.open(video_file, api));
|
||||
ASSERT_TRUE(cap.isOpened()) << "Can't open the video: " << video_file << " with backend " << api << std::endl;
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
{
|
||||
cap.release();
|
||||
}
|
||||
|
||||
void orientationCheck(double angle, int width, int height)
|
||||
{
|
||||
EXPECT_EQ(angle, cap.get(CAP_PROP_ORIENTATION_META));
|
||||
EXPECT_EQ(width, (int)cap.get(CAP_PROP_FRAME_WIDTH));
|
||||
EXPECT_EQ(height, (int)cap.get(CAP_PROP_FRAME_HEIGHT));
|
||||
|
||||
Mat frame;
|
||||
cap >> frame;
|
||||
|
||||
ASSERT_EQ(width, frame.cols);
|
||||
ASSERT_EQ(height, frame.rows);
|
||||
}
|
||||
|
||||
VideoCapture cap;
|
||||
};
|
||||
|
||||
// Related issues:
|
||||
// - https://github.com/opencv/opencv/issues/26795
|
||||
// - https://github.com/opencv/opencv/issues/15499
|
||||
TEST_P(VideoCaptureAPITests, mp4_orientation_default_auto)
|
||||
{
|
||||
EXPECT_TRUE(cap.get(CAP_PROP_ORIENTATION_AUTO));
|
||||
orientationCheck(90., 270, 480);
|
||||
}
|
||||
|
||||
TEST_P(VideoCaptureAPITests, mp4_orientation_forced)
|
||||
{
|
||||
EXPECT_TRUE(cap.set(CAP_PROP_ORIENTATION_AUTO, false));
|
||||
orientationCheck(90., 480, 270);
|
||||
}
|
||||
|
||||
TEST_P(VideoCaptureAPITests, mp4_orientation_switch)
|
||||
{
|
||||
SCOPED_TRACE("Initial orientation with autorotation");
|
||||
orientationCheck(90., 270, 480);
|
||||
SCOPED_TRACE("Disabled autorotation");
|
||||
EXPECT_TRUE(cap.set(CAP_PROP_ORIENTATION_AUTO, false));
|
||||
EXPECT_FALSE(cap.get(CAP_PROP_ORIENTATION_AUTO));
|
||||
orientationCheck(90., 480, 270);
|
||||
}
|
||||
|
||||
|
||||
static cv::VideoCaptureAPIs supported_backends[] = {
|
||||
#ifdef HAVE_AVFOUNDATION
|
||||
CAP_AVFOUNDATION,
|
||||
#endif
|
||||
CAP_FFMPEG
|
||||
};
|
||||
|
||||
inline static std::string VideoCaptureAPITests_name_printer(const testing::TestParamInfo<VideoCaptureAPITests::ParamType>& info)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << getBackendNameSafe(info.param);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(videoio, VideoCaptureAPITests, testing::ValuesIn(supported_backends), VideoCaptureAPITests_name_printer);
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,105 @@
|
||||
// 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"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
enum VideoBackendMode
|
||||
{
|
||||
MODE_CAMERA,
|
||||
MODE_STREAM,
|
||||
MODE_WRITER,
|
||||
};
|
||||
|
||||
static
|
||||
void dumpBackendInfo(VideoCaptureAPIs backend, enum VideoBackendMode mode)
|
||||
{
|
||||
std::string name;
|
||||
try
|
||||
{
|
||||
name = videoio_registry::getBackendName(backend);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
ADD_FAILURE() << "Can't query name of backend=" << backend << ": " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ADD_FAILURE() << "Can't query name of backend=" << backend << ": unknown C++ exception";
|
||||
}
|
||||
bool isBuiltIn = true;
|
||||
try
|
||||
{
|
||||
isBuiltIn = videoio_registry::isBackendBuiltIn(backend);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
ADD_FAILURE() << "Failed isBackendBuiltIn(backend=" << backend << "): " << e.what();
|
||||
cout << name << " - UNKNOWN TYPE" << endl;
|
||||
return;
|
||||
}
|
||||
if (isBuiltIn)
|
||||
{
|
||||
cout << name << " - BUILTIN" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string description = "NO_DESCRIPTION";
|
||||
int version_ABI = 0;
|
||||
int version_API = 0;
|
||||
try
|
||||
{
|
||||
if (mode == MODE_CAMERA)
|
||||
description = videoio_registry::getCameraBackendPluginVersion(backend, version_ABI, version_API);
|
||||
else if (mode == MODE_STREAM)
|
||||
description = videoio_registry::getStreamBackendPluginVersion(backend, version_ABI, version_API);
|
||||
else if (mode == MODE_WRITER)
|
||||
description = videoio_registry::getWriterBackendPluginVersion(backend, version_ABI, version_API);
|
||||
else
|
||||
CV_Error(Error::StsInternal, "");
|
||||
cout << name << " - PLUGIN (" << description << ") ABI=" << version_ABI << " API=" << version_API << endl;
|
||||
return;
|
||||
}
|
||||
catch (const cv::Exception& e)
|
||||
{
|
||||
if (e.code == Error::StsNotImplemented)
|
||||
{
|
||||
cout << name << " - PLUGIN - NOT LOADED" << endl;
|
||||
return;
|
||||
}
|
||||
ADD_FAILURE() << "Failed getBackendPluginDescription(backend=" << backend << "): " << e.what();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
ADD_FAILURE() << "Failed getBackendPluginDescription(backend=" << backend << "): " << e.what();
|
||||
}
|
||||
cout << name << " - PLUGIN (ERROR on quering information)" << endl;
|
||||
}
|
||||
|
||||
TEST(VideoIO_Plugins, query)
|
||||
{
|
||||
const std::vector<cv::VideoCaptureAPIs> camera_backends = cv::videoio_registry::getCameraBackends();
|
||||
cout << "== Camera APIs (" << camera_backends.size() << "):" << endl;
|
||||
for (auto backend : camera_backends)
|
||||
{
|
||||
dumpBackendInfo(backend, MODE_CAMERA);
|
||||
}
|
||||
|
||||
const std::vector<cv::VideoCaptureAPIs> stream_backends = cv::videoio_registry::getStreamBackends();
|
||||
cout << "== Stream capture APIs (" << stream_backends.size() << "):" << endl;
|
||||
for (auto backend : stream_backends)
|
||||
{
|
||||
dumpBackendInfo(backend, MODE_STREAM);
|
||||
}
|
||||
|
||||
const std::vector<cv::VideoCaptureAPIs> writer_backends = cv::videoio_registry::getWriterBackends();
|
||||
cout << "== Writer APIs (" << writer_backends.size() << "):" << endl;
|
||||
for (auto backend : writer_backends)
|
||||
{
|
||||
dumpBackendInfo(backend, MODE_WRITER);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,158 @@
|
||||
// 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.
|
||||
#ifndef __OPENCV_TEST_PRECOMP_HPP__
|
||||
#define __OPENCV_TEST_PRECOMP_HPP__
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include "opencv2/ts.hpp"
|
||||
#include "opencv2/ts/ocl_test.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/videoio/registry.hpp"
|
||||
#include "opencv2/core/private.hpp"
|
||||
#include "opencv2/core/utils/configuration.private.hpp"
|
||||
|
||||
namespace cv {
|
||||
|
||||
static inline
|
||||
std::ostream& operator<<(std::ostream& out, const VideoCaptureAPIs& api)
|
||||
{
|
||||
out << cv::videoio_registry::getBackendName(api); return out;
|
||||
}
|
||||
|
||||
static inline
|
||||
std::ostream& operator<<(std::ostream& out, const VideoAccelerationType& va_type)
|
||||
{
|
||||
struct {
|
||||
VideoAccelerationType va_type;
|
||||
const char* str;
|
||||
} va_types[] = {
|
||||
{VIDEO_ACCELERATION_ANY, "ANY"},
|
||||
{VIDEO_ACCELERATION_NONE, "NONE"},
|
||||
{VIDEO_ACCELERATION_D3D11, "D3D11"},
|
||||
{VIDEO_ACCELERATION_VAAPI, "VAAPI"},
|
||||
{VIDEO_ACCELERATION_MFX, "MFX"},
|
||||
{VIDEO_ACCELERATION_DRM, "DRM"},
|
||||
};
|
||||
for (const auto& va : va_types) {
|
||||
if (va_type == va.va_type) {
|
||||
out << va.str;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
out << cv::format("UNKNOWN(0x%ux)", static_cast<unsigned int>(va_type));
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline void PrintTo(const cv::VideoCaptureAPIs& api, std::ostream* os)
|
||||
{
|
||||
*os << cv::videoio_registry::getBackendName(api);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
inline std::string fourccToString(int fourcc)
|
||||
{
|
||||
return cv::format("%c%c%c%c",
|
||||
(char)(fourcc & 255),
|
||||
(char)((fourcc >> 8) & 255),
|
||||
(char)((fourcc >> 16) & 255),
|
||||
(char)((fourcc >> 24) & 255));
|
||||
}
|
||||
|
||||
inline std::string fourccToStringSafe(int fourcc)
|
||||
{
|
||||
std::string res = fourccToString(fourcc);
|
||||
// TODO: return hex values for invalid characters
|
||||
std::transform(res.begin(), res.end(), res.begin(),
|
||||
[](char c) -> char { return (c >= '0' && c <= 'z') ? c : (c == ' ' ? '_' : 'x'); });
|
||||
return res;
|
||||
}
|
||||
|
||||
inline int fourccFromString(const std::string &fourcc)
|
||||
{
|
||||
if (fourcc.size() != 4) return 0;
|
||||
return cv::VideoWriter::fourcc(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
|
||||
}
|
||||
|
||||
inline std::string extToStringSafe(const std::string & ext)
|
||||
{
|
||||
std::string res;
|
||||
const bool start_with_dot = (ext.size() > 0) && (ext[0] == '.');
|
||||
std::transform(start_with_dot ? ext.begin() + 1 : ext.begin(), ext.end(), std::back_inserter(res),
|
||||
[](char c) -> char { return (c >= '0' && c <= 'z') ? c : ((c == ' ' || c == '.') ? '_' : 'x'); });
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::string getExtensionSafe(const std::string & fname)
|
||||
{
|
||||
std::string fext(std::find(fname.begin(), fname.end(), '.'), fname.end());
|
||||
if (fext.size() == 0)
|
||||
return std::string("NOEXT");
|
||||
else
|
||||
return extToStringSafe(fext);
|
||||
}
|
||||
|
||||
inline std::string getBackendNameSafe(const cv::VideoCaptureAPIs & api)
|
||||
{
|
||||
const std::string res = cv::videoio_registry::getBackendName(api);
|
||||
if (res.substr(0, 7) == "Unknown")
|
||||
{
|
||||
std::ostringstream os; os << "BACKEND_" << (size_t)api; return os.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
inline void generateFrame(int i, int frame_count, cv::Mat & frame)
|
||||
{
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
int offset = (((i * 5) % frame_count) - frame_count / 2) * (frame.cols / 2) / frame_count;
|
||||
frame(cv::Rect(0, 0, frame.cols / 2 + offset, frame.rows)) = Scalar(255, 255, 255);
|
||||
frame(cv::Rect(frame.cols / 2 + offset, 0, frame.cols - frame.cols / 2 - offset, frame.rows)) = Scalar(0, 0, 0);
|
||||
std::string str = cv::format("%02d", i+1);
|
||||
int baseLine = 0;
|
||||
Size box = getTextSize(str, FONT_HERSHEY_COMPLEX, 2, 5, &baseLine);
|
||||
putText(frame, str, Point((frame.cols - box.width) / 2, (frame.rows - box.height) / 2 + baseLine),
|
||||
FONT_HERSHEY_COMPLEX, 2, Scalar(0, 0, 255), 5, LINE_AA);
|
||||
Point p(i * frame.cols / (frame_count - 1), i * frame.rows / (frame_count - 1));
|
||||
circle(frame, p, 50, Scalar(200, 25, 55), 8, LINE_AA);
|
||||
#if 0
|
||||
imshow("frame", frame);
|
||||
waitKey();
|
||||
#endif
|
||||
}
|
||||
|
||||
class BunnyParameters
|
||||
{
|
||||
public:
|
||||
inline static int getWidth() { return 672; }
|
||||
inline static int getHeight() { return 384; }
|
||||
inline static int getFps() { return 24; }
|
||||
inline static double getTime() { return 5.21; }
|
||||
inline static int getCount() { return cvRound(getFps() * getTime()); }
|
||||
inline static std::string getFilename(const std::string &ext)
|
||||
{
|
||||
return cvtest::TS::ptr()->get_data_path() + "video/big_buck_bunny" + ext;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static inline bool isBackendAvailable(cv::VideoCaptureAPIs api, const std::vector<cv::VideoCaptureAPIs>& api_list)
|
||||
{
|
||||
for (size_t i = 0; i < api_list.size(); i++)
|
||||
{
|
||||
if (api_list[i] == api)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,178 @@
|
||||
// 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.
|
||||
|
||||
// Reference: https://www.kernel.org/doc/html/v4.8/media/v4l-drivers/vivid.html
|
||||
|
||||
// create 1 virtual device of type CAP (0x1) at /dev/video10
|
||||
// sudo modprobe vivid ndevs=1 node_types=0x1 vid_cap_nr=10
|
||||
// make sure user have read/write access (e.g. via group 'video')
|
||||
// $ ls -l /dev/video10
|
||||
// crw-rw----+ 1 root video ... /dev/video10
|
||||
// set environment variable:
|
||||
// export OPENCV_TEST_V4L2_VIVID_DEVICE=/dev/video10
|
||||
// run v4l2 tests:
|
||||
// opencv_test_videoio --gtest_filter=*videoio_v4l2*
|
||||
|
||||
|
||||
#ifdef HAVE_CAMV4L2
|
||||
|
||||
// #define DUMP_CAMERA_FRAME
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
#include <opencv2/core/utils/configuration.private.hpp>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
// workarounds for older versions
|
||||
#ifndef v4l2_fourcc_be
|
||||
#define v4l2_fourcc_be(a, b, c, d) (v4l2_fourcc(a, b, c, d) | (1U << 31))
|
||||
#endif
|
||||
#ifndef V4L2_PIX_FMT_Y10
|
||||
#define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ')
|
||||
#endif
|
||||
#ifndef V4L2_PIX_FMT_Y12
|
||||
#define V4L2_PIX_FMT_Y12 v4l2_fourcc('Y', '1', '2', ' ')
|
||||
#endif
|
||||
#ifndef V4L2_PIX_FMT_ABGR32
|
||||
#define V4L2_PIX_FMT_ABGR32 v4l2_fourcc('A', 'R', '2', '4')
|
||||
#endif
|
||||
#ifndef V4L2_PIX_FMT_XBGR32
|
||||
#define V4L2_PIX_FMT_XBGR32 v4l2_fourcc('X', 'R', '2', '4')
|
||||
#endif
|
||||
#ifndef V4L2_PIX_FMT_Y16
|
||||
#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ')
|
||||
#endif
|
||||
#ifndef V4L2_PIX_FMT_Y16_BE
|
||||
#define V4L2_PIX_FMT_Y16_BE v4l2_fourcc_be('Y', '1', '6', ' ')
|
||||
#endif
|
||||
|
||||
|
||||
using namespace cv;
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
struct Format_Channels_Depth
|
||||
{
|
||||
uint32_t pixel_format;
|
||||
uint8_t channels;
|
||||
uint8_t depth;
|
||||
float mul_width;
|
||||
float mul_height;
|
||||
};
|
||||
|
||||
typedef testing::TestWithParam<Format_Channels_Depth> videoio_v4l2;
|
||||
|
||||
TEST_P(videoio_v4l2, formats)
|
||||
{
|
||||
utils::Paths devs = utils::getConfigurationParameterPaths("OPENCV_TEST_V4L2_VIVID_DEVICE");
|
||||
if (devs.size() != 1)
|
||||
{
|
||||
throw SkipTestException("OPENCV_TEST_V4L2_VIVID_DEVICE is not set");
|
||||
}
|
||||
const string device = devs[0];
|
||||
const Size sz(640, 480);
|
||||
const Format_Channels_Depth params = GetParam();
|
||||
const Size esz(sz.width * params.mul_width, sz.height * params.mul_height);
|
||||
|
||||
{
|
||||
// Case with RAW output
|
||||
VideoCapture cap;
|
||||
ASSERT_TRUE(cap.open(device, CAP_V4L2));
|
||||
// VideoCapture will set device's format automatically, vivid device will accept it
|
||||
ASSERT_TRUE(cap.set(CAP_PROP_FOURCC, params.pixel_format));
|
||||
ASSERT_TRUE(cap.set(CAP_PROP_CONVERT_RGB, false));
|
||||
for (size_t idx = 0; idx < 3; ++idx)
|
||||
{
|
||||
Mat img;
|
||||
EXPECT_TRUE(cap.grab());
|
||||
EXPECT_TRUE(cap.retrieve(img));
|
||||
if (params.pixel_format == V4L2_PIX_FMT_SRGGB8 ||
|
||||
params.pixel_format == V4L2_PIX_FMT_SBGGR8 ||
|
||||
params.pixel_format == V4L2_PIX_FMT_SGBRG8 ||
|
||||
params.pixel_format == V4L2_PIX_FMT_SGRBG8)
|
||||
{
|
||||
EXPECT_EQ((size_t)esz.area(), img.total());
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_EQ(esz, img.size());
|
||||
}
|
||||
EXPECT_EQ(params.channels, img.channels());
|
||||
EXPECT_EQ(params.depth, img.depth());
|
||||
}
|
||||
}
|
||||
{
|
||||
// case with BGR output
|
||||
VideoCapture cap;
|
||||
ASSERT_TRUE(cap.open(device, CAP_V4L2));
|
||||
// VideoCapture will set device's format automatically, vivid device will accept it
|
||||
ASSERT_TRUE(cap.set(CAP_PROP_FOURCC, params.pixel_format));
|
||||
for (size_t idx = 0; idx < 3; ++idx)
|
||||
{
|
||||
Mat img;
|
||||
EXPECT_TRUE(cap.grab());
|
||||
EXPECT_TRUE(cap.retrieve(img));
|
||||
EXPECT_EQ(sz, img.size());
|
||||
EXPECT_EQ(3, img.channels());
|
||||
EXPECT_EQ(CV_8U, img.depth());
|
||||
#ifdef DUMP_CAMERA_FRAME
|
||||
std::string img_name = "frame_" + fourccToStringSafe(params.pixel_format);
|
||||
// V4L2 flag for big-endian formats
|
||||
if(params.pixel_format & (1 << 31))
|
||||
img_name += "-BE";
|
||||
cv::imwrite(img_name + ".png", img);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<Format_Channels_Depth> all_params = {
|
||||
{ V4L2_PIX_FMT_YVU420, 1, CV_8U, 1.f, 1.5f },
|
||||
{ V4L2_PIX_FMT_YUV420, 1, CV_8U, 1.f, 1.5f },
|
||||
{ V4L2_PIX_FMT_NV12, 1, CV_8U, 1.f, 1.5f },
|
||||
{ V4L2_PIX_FMT_NV21, 1, CV_8U, 1.f, 1.5f },
|
||||
{ V4L2_PIX_FMT_YUV411P, 3, CV_8U, 1.f, 1.f },
|
||||
// { V4L2_PIX_FMT_MJPEG, 1, CV_8U, 1.f, 1.f },
|
||||
// { V4L2_PIX_FMT_JPEG, 1, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_YUYV, 2, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_UYVY, 2, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_SN9C10X, 3, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_SRGGB8, 1, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_SBGGR8, 1, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_SGBRG8, 1, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_SGRBG8, 1, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_RGB24, 3, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_Y16, 1, CV_16U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_Y16_BE, 1, CV_16U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_Y10, 1, CV_16U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_GREY, 1, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_BGR24, 3, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_XBGR32, 4, CV_8U, 1.f, 1.f },
|
||||
{ V4L2_PIX_FMT_ABGR32, 4, CV_8U, 1.f, 1.f },
|
||||
};
|
||||
|
||||
inline static std::string param_printer(const testing::TestParamInfo<videoio_v4l2::ParamType>& info)
|
||||
{
|
||||
return fourccToStringSafe(info.param.pixel_format);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*videoio_v4l2*/, videoio_v4l2, ValuesIn(all_params), param_printer);
|
||||
|
||||
TEST(videoio_ffmpeg, camera_index)
|
||||
{
|
||||
utils::Paths devs = utils::getConfigurationParameterPaths("OPENCV_TEST_V4L2_VIVID_DEVICE");
|
||||
if (devs.size() != 1)
|
||||
{
|
||||
throw SkipTestException("OPENCV_TEST_V4L2_VIVID_DEVICE is not set");
|
||||
}
|
||||
VideoCapture cap;
|
||||
ASSERT_TRUE(cap.open(0, CAP_FFMPEG));
|
||||
Mat frame;
|
||||
ASSERT_TRUE(cap.read(frame));
|
||||
EXPECT_EQ(CAP_PROP_UNKNOWN, cap.get(CV__CAP_PROP_LATEST));
|
||||
ASSERT_FALSE(frame.empty());
|
||||
}
|
||||
|
||||
}} // opencv_test::<anonymous>::
|
||||
|
||||
#endif // HAVE_CAMV4L2
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user