[opencv] 24/251: videoio: fixes for GStreamer support
Nobuhiro Iwamatsu
iwamatsu at moszumanska.debian.org
Sun Aug 27 23:27:20 UTC 2017
This is an automated email from the git hooks/post-receive script.
iwamatsu pushed a commit to annotated tag 3.3.0
in repository opencv.
commit cc862e996ebb0e10886e644c637a1e8e4a0b7901
Author: Alexander Alekhin <alexander.alekhin at intel.com>
Date: Wed Jul 5 13:45:08 2017 +0300
videoio: fixes for GStreamer support
- emulated frame counter (with autodetection of GStreamer broken behavior)
- skip 'seek' tests if seeking is not supported by backend
- update 'fps' and total frames checks (increase error tolerance)
- update synthetic image generation
---
modules/videoio/src/cap_gstreamer.cpp | 126 ++++++++++++++++++++++++++++++---
modules/videoio/test/test_mfx.cpp | 9 +--
modules/videoio/test/test_precomp.hpp | 12 +++-
modules/videoio/test/test_video_io.cpp | 103 ++++++++++++++++++---------
4 files changed, 195 insertions(+), 55 deletions(-)
diff --git a/modules/videoio/src/cap_gstreamer.cpp b/modules/videoio/src/cap_gstreamer.cpp
index 552c1cb..a31b05f 100644
--- a/modules/videoio/src/cap_gstreamer.cpp
+++ b/modules/videoio/src/cap_gstreamer.cpp
@@ -168,6 +168,10 @@ protected:
gint width;
gint height;
double fps;
+
+ bool isPosFramesSupported;
+ bool isPosFramesEmulated;
+ gint64 emulatedFrameNumber;
};
/*!
@@ -191,6 +195,10 @@ void CvCapture_GStreamer::init()
width = -1;
height = -1;
fps = -1;
+
+ isPosFramesSupported = false;
+ isPosFramesEmulated = false;
+ emulatedFrameNumber = -1;
}
/*!
@@ -212,6 +220,9 @@ void CvCapture_GStreamer::close()
width = -1;
height = -1;
fps = -1;
+ isPosFramesSupported = false;
+ isPosFramesEmulated = false;
+ emulatedFrameNumber = -1;
}
/*!
@@ -253,6 +264,9 @@ bool CvCapture_GStreamer::grabFrame()
if(!buffer)
return false;
+ if (isPosFramesEmulated)
+ emulatedFrameNumber++;
+
return true;
}
@@ -408,6 +422,9 @@ void CvCapture_GStreamer::startPipeline()
return;
}
+ if (isPosFramesEmulated)
+ emulatedFrameNumber = 0;
+
//printf("state now playing\n");
handleMessage(pipeline);
__END__;
@@ -847,6 +864,8 @@ bool CvCapture_GStreamer::open( int type, const char* filename )
duration = -1;
}
+ handleMessage(pipeline);
+
GstPad* pad = gst_element_get_static_pad(sink, "sink");
#if GST_VERSION_MAJOR == 0
GstCaps* buffer_caps = gst_pad_get_caps(pad);
@@ -873,9 +892,32 @@ bool CvCapture_GStreamer::open( int type, const char* filename )
fps = (double)num/(double)denom;
- // GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline")
- if (file)
- stopPipeline();
+ {
+ GstFormat format_;
+ gint64 value_ = -1;
+ gboolean status_;
+
+ format_ = GST_FORMAT_DEFAULT;
+#if GST_VERSION_MAJOR == 0
+#define FORMAT &format_
+#else
+#define FORMAT format_
+#endif
+ status_ = gst_element_query_position(pipeline, FORMAT, &value_);
+#undef FORMAT
+ if (!status_ || value_ != 0 || duration < 0)
+ {
+ CV_WARN(cv::format("Cannot query video position: status=%d value=%lld duration=%lld\n",
+ (int)status_, (long long int)value_, (long long int)duration).c_str());
+ isPosFramesSupported = false;
+ isPosFramesEmulated = true;
+ emulatedFrameNumber = 0;
+ }
+ else
+ isPosFramesSupported = true;
+ }
+
+ GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline");
}
__END__;
@@ -914,14 +956,22 @@ double CvCapture_GStreamer::getProperty( int propId ) const
format = GST_FORMAT_TIME;
status = gst_element_query_position(sink, FORMAT, &value);
if(!status) {
+ handleMessage(pipeline);
CV_WARN("GStreamer: unable to query position of stream");
return 0;
}
return value * 1e-6; // nano seconds to milli seconds
case CV_CAP_PROP_POS_FRAMES:
+ if (!isPosFramesSupported)
+ {
+ if (isPosFramesEmulated)
+ return emulatedFrameNumber;
+ return 0; // TODO getProperty() "unsupported" value should be changed
+ }
format = GST_FORMAT_DEFAULT;
status = gst_element_query_position(sink, FORMAT, &value);
if(!status) {
+ handleMessage(pipeline);
CV_WARN("GStreamer: unable to query position of stream");
return 0;
}
@@ -930,6 +980,7 @@ double CvCapture_GStreamer::getProperty( int propId ) const
format = GST_FORMAT_PERCENT;
status = gst_element_query_position(sink, FORMAT, &value);
if(!status) {
+ handleMessage(pipeline);
CV_WARN("GStreamer: unable to query position of stream");
return 0;
}
@@ -1013,24 +1064,75 @@ bool CvCapture_GStreamer::setProperty( int propId, double value )
flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE);
if(!gst_element_seek_simple(GST_ELEMENT(pipeline), format,
flags, (gint64) (value * GST_MSECOND))) {
+ handleMessage(pipeline);
CV_WARN("GStreamer: unable to seek");
}
+ else
+ {
+ if (isPosFramesEmulated)
+ {
+ if (value == 0)
+ {
+ emulatedFrameNumber = 0;
+ return true;
+ }
+ else
+ {
+ isPosFramesEmulated = false; // reset frame counter emulation
+ }
+ }
+ }
break;
case CV_CAP_PROP_POS_FRAMES:
+ {
+ if (!isPosFramesSupported)
+ {
+ if (isPosFramesEmulated)
+ {
+ if (value == 0)
+ {
+ restartPipeline();
+ emulatedFrameNumber = 0;
+ return true;
+ }
+ }
+ return false;
+ }
format = GST_FORMAT_DEFAULT;
flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE);
if(!gst_element_seek_simple(GST_ELEMENT(pipeline), format,
flags, (gint64) value)) {
+ handleMessage(pipeline);
CV_WARN("GStreamer: unable to seek");
+ break;
}
- break;
+ // wait for status update
+ gst_element_get_state(pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+ return true;
+ }
case CV_CAP_PROP_POS_AVI_RATIO:
format = GST_FORMAT_PERCENT;
flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE);
if(!gst_element_seek_simple(GST_ELEMENT(pipeline), format,
flags, (gint64) (value * GST_FORMAT_PERCENT_MAX))) {
+ handleMessage(pipeline);
CV_WARN("GStreamer: unable to seek");
}
+ else
+ {
+ if (isPosFramesEmulated)
+ {
+ if (value == 0)
+ {
+ emulatedFrameNumber = 0;
+ return true;
+ }
+ else
+ {
+ isPosFramesEmulated = false; // reset frame counter emulation
+ }
+ }
+ }
break;
case CV_CAP_PROP_FRAME_WIDTH:
if(value > 0)
@@ -1719,7 +1821,7 @@ void handleMessage(GstElement * pipeline)
while(gst_bus_have_pending(bus)) {
msg = gst_bus_pop(bus);
- //printf("Got %s message\n", GST_MESSAGE_TYPE_NAME(msg));
+ //printf("\t\tGot %s message\n", GST_MESSAGE_TYPE_NAME(msg));
if(gst_is_missing_plugin_message(msg))
{
@@ -1731,13 +1833,15 @@ void handleMessage(GstElement * pipeline)
case GST_MESSAGE_STATE_CHANGED:
GstState oldstate, newstate, pendstate;
gst_message_parse_state_changed(msg, &oldstate, &newstate, &pendstate);
- //fprintf(stderr, "state changed from %s to %s (pending: %s)\n", gst_element_state_get_name(oldstate),
+ //fprintf(stderr, "\t\t%s: state changed from %s to %s (pending: %s)\n",
+ // gst_element_get_name(GST_MESSAGE_SRC (msg)),
+ // gst_element_state_get_name(oldstate),
// gst_element_state_get_name(newstate), gst_element_state_get_name(pendstate));
break;
case GST_MESSAGE_ERROR:
gst_message_parse_error(msg, &err, &debug);
- fprintf(stderr, "GStreamer Plugin: Embedded video playback halted; module %s reported: %s\n",
- gst_element_get_name(GST_MESSAGE_SRC (msg)), err->message);
+ //fprintf(stderr, "\t\tGStreamer Plugin: Embedded video playback halted; module %s reported: %s\n",
+ // gst_element_get_name(GST_MESSAGE_SRC (msg)), err->message);
g_error_free(err);
g_free(debug);
@@ -1745,14 +1849,14 @@ void handleMessage(GstElement * pipeline)
gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
break;
case GST_MESSAGE_EOS:
- //fprintf(stderr, "reached the end of the stream.");
+ //fprintf(stderr, "\t\treached the end of the stream.");
break;
case GST_MESSAGE_STREAM_STATUS:
gst_message_parse_stream_status(msg,&tp,&elem);
- //fprintf(stderr, "stream status: elem %s, %i\n", GST_ELEMENT_NAME(elem), tp);
+ //fprintf(stderr, "\t\tstream status: elem %s, %i\n", GST_ELEMENT_NAME(elem), tp);
break;
default:
- //fprintf(stderr, "unhandled message %s\n",GST_MESSAGE_TYPE_NAME(msg));
+ //fprintf(stderr, "\t\tunhandled message %s\n",GST_MESSAGE_TYPE_NAME(msg));
break;
}
}
diff --git a/modules/videoio/test/test_mfx.cpp b/modules/videoio/test/test_mfx.cpp
index 1149bb2..875b692 100644
--- a/modules/videoio/test/test_mfx.cpp
+++ b/modules/videoio/test/test_mfx.cpp
@@ -71,14 +71,7 @@ const int FRAME_COUNT = 20;
inline void generateFrame(int i, Mat & frame)
{
- frame = 0;
- ostringstream buf; buf << "Frame " << setw(2) << setfill('0') << i + 1;
- int baseLine = 0;
- Size box = getTextSize(buf.str(), FONT_HERSHEY_COMPLEX, 2, 5, &baseLine);
- putText(frame, buf.str(), Point((frame.cols - box.width) / 2, (frame.rows - box.height) / 2 + baseLine),
- FONT_HERSHEY_COMPLEX, 2, Scalar(255, 255, 255), 5, LINE_AA);
- Point p(i * frame.cols / (FRAME_COUNT - 1), i * frame.rows / (FRAME_COUNT - 1));
- circle(frame, p, 20, Scalar(200, 25, 55), 5, LINE_AA);
+ generateFrame(i, FRAME_COUNT, frame);
}
inline int fourccByExt(const String &ext)
diff --git a/modules/videoio/test/test_precomp.hpp b/modules/videoio/test/test_precomp.hpp
index a7706fd..bd56a72 100644
--- a/modules/videoio/test/test_precomp.hpp
+++ b/modules/videoio/test/test_precomp.hpp
@@ -33,14 +33,20 @@ inline void generateFrame(int i, int FRAME_COUNT, cv::Mat & frame)
{
using namespace cv;
using namespace std;
- frame = Scalar(30, 140, 10);
+ 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);
ostringstream buf; buf << "Frame " << setw(2) << setfill('0') << i + 1;
int baseLine = 0;
Size box = getTextSize(buf.str(), FONT_HERSHEY_COMPLEX, 2, 5, &baseLine);
putText(frame, buf.str(), Point((frame.cols - box.width) / 2, (frame.rows - box.height) / 2 + baseLine),
- FONT_HERSHEY_COMPLEX, 2, Scalar(255, 255, 255), 5, LINE_AA);
+ 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, 20, Scalar(200, 25, 55), 5, LINE_AA);
+ circle(frame, p, 50, Scalar(200, 25, 55), 8, LINE_AA);
+#if 0
+ imshow("frame", frame);
+ waitKey();
+#endif
}
#endif
diff --git a/modules/videoio/test/test_video_io.cpp b/modules/videoio/test/test_video_io.cpp
index b8bb422..d2eae6f 100644
--- a/modules/videoio/test/test_video_io.cpp
+++ b/modules/videoio/test/test_video_io.cpp
@@ -61,25 +61,44 @@ protected:
virtual void checkFrameCount(int &) {}
void checkFrameRead(int idx, VideoCapture & cap)
{
+ //int frameID = (int)cap.get(CAP_PROP_POS_FRAMES);
Mat img; cap >> img;
- ASSERT_FALSE(img.empty());
+ //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)
{
- ASSERT_TRUE(cap.set(CAP_PROP_POS_FRAMES, idx));
- ASSERT_EQ(idx, (int)cap.get(CAP_PROP_POS_FRAMES));
+ 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()
{
VideoCapture cap(video_file);
- ASSERT_TRUE(cap.isOpened());
+ if (!cap.isOpened())
+ {
+ std::cout << "SKIP test: Can't open video: " << video_file << std::endl;
+ return;
+ }
int n_frames = (int)cap.get(CAP_PROP_FRAME_COUNT);
- ASSERT_GT(n_frames, 0);
- checkFrameCount(n_frames);
+ 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");
@@ -89,25 +108,32 @@ public:
}
}
- if (ext != "mpg" && ext != "wmv")
+ bool canSeek = cap.set(CAP_PROP_POS_FRAMES, 0);
+ if (!canSeek)
{
- 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);
- }
+ 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 = 1; k < n_frames; k += 20)
+ 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);
+ }
+ }
}
};
@@ -124,7 +150,11 @@ public:
void doFrameCountTest()
{
VideoCapture cap(video_file);
- ASSERT_TRUE(cap.isOpened());
+ if (!cap.isOpened())
+ {
+ std::cout << "SKIP test: Can't open video: " << video_file << std::endl;
+ return;
+ }
const int width_gt = 672;
const int height_gt = 384;
@@ -135,16 +165,20 @@ public:
EXPECT_EQ(width_gt, cap.get(CAP_PROP_FRAME_WIDTH));
EXPECT_EQ(height_gt, cap.get(CAP_PROP_FRAME_HEIGHT));
- int fps_prop = (int)cap.get(CAP_PROP_FPS);
- EXPECT_EQ(fps_gt, fps_prop);
+ double fps_prop = cap.get(CAP_PROP_FPS);
+ if (fps_prop > 0)
+ EXPECT_NEAR(fps_prop, fps_gt, 1);
+ else
+ std::cout << "FPS is not available. SKIP check." << std::endl;
int count_prop = (int)cap.get(CAP_PROP_FRAME_COUNT);
- ASSERT_GT(count_prop, 0);
+
// mpg file reports 5.08 sec * 24 fps => property returns 122 frames
// but actual number of frames returned is 125
if (ext != "mpg")
{
- EXPECT_EQ(count_gt, count_prop);
+ if (count_prop > 0)
+ EXPECT_EQ(count_gt, count_prop);
}
int count_actual = 0;
@@ -158,7 +192,10 @@ public:
EXPECT_EQ(height_gt, frame.rows);
count_actual += 1;
}
- EXPECT_EQ(count_gt, count_actual);
+ if (count_prop > 0)
+ EXPECT_NEAR(count_gt, count_actual, 1);
+ else
+ std::cout << "Frames counter is not available. Actual frames: " << count_actual << ". SKIP check." << std::endl;
}
};
@@ -268,30 +305,30 @@ Ext_Fourcc_PSNR synthetic_params[] = {
#ifdef HAVE_MSMF
#if !defined(_M_ARM)
- makeParam("wmv", "WMV1", 39.f),
- makeParam("wmv", "WMV2", 39.f),
+ makeParam("wmv", "WMV1", 30.f),
+ makeParam("wmv", "WMV2", 30.f),
#endif
- makeParam("wmv", "WMV3", 39.f),
- makeParam("avi", "H264", 39.f),
- makeParam("wmv", "WVC1", 39.f),
+ makeParam("wmv", "WMV3", 30.f),
+ makeParam("avi", "H264", 30.f),
+ makeParam("wmv", "WVC1", 30.f),
#else // HAVE_MSMF
- makeParam("avi", "XVID", 35.f),
- makeParam("avi", "MPEG", 35.f),
- makeParam("avi", "IYUV", 35.f),
- makeParam("mkv", "XVID", 35.f),
- makeParam("mkv", "MPEG", 35.f),
- makeParam("mkv", "MJPG", 35.f),
+ makeParam("avi", "XVID", 30.f),
+ makeParam("avi", "MPEG", 30.f),
+ makeParam("avi", "IYUV", 30.f),
+ makeParam("mkv", "XVID", 30.f),
+ makeParam("mkv", "MPEG", 30.f),
+ makeParam("mkv", "MJPG", 30.f),
#ifndef HAVE_GSTREAMER
- makeParam("mov", "mp4v", 35.f),
+ makeParam("mov", "mp4v", 30.f),
#endif
#endif // HAVE_MSMF
#endif // HAVE_VIDEO_INPUT && HAVE_VIDEO_OUTPUT ...
- makeParam("avi", "MJPG", 41.f)
+ makeParam("avi", "MJPG", 30.f)
};
Size all_sizes[] = {
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/opencv.git
More information about the debian-science-commits
mailing list