in modules/videoio/src/cap_gstreamer.cpp [555:830]
bool CvCapture_GStreamer::open( int type, const char* filename )
{
CV_FUNCNAME("cvCaptureFromCAM_GStreamer");
__BEGIN__;
gst_initializer::init();
bool file = false;
bool stream = false;
bool manualpipeline = false;
char *uri = NULL;
uridecodebin = NULL;
GstElementFactory * testfac;
GstStateChangeReturn status;
if (type == CV_CAP_GSTREAMER_V4L){
testfac = gst_element_factory_find("v4lsrc");
if (!testfac){
return false;
}
g_object_unref(G_OBJECT(testfac));
filename = "v4lsrc ! " COLOR_ELEM " ! appsink";
}
if (type == CV_CAP_GSTREAMER_V4L2){
testfac = gst_element_factory_find("v4l2src");
if (!testfac){
return false;
}
g_object_unref(G_OBJECT(testfac));
filename = "v4l2src ! " COLOR_ELEM " ! appsink";
}
// test if we have a valid uri. If so, open it with an uridecodebin
// else, we might have a file or a manual pipeline.
// if gstreamer cannot parse the manual pipeline, we assume we were given and
// ordinary file path.
if(!gst_uri_is_valid(filename))
{
uri = realpath(filename, NULL);
stream = false;
if(uri)
{
uri = g_filename_to_uri(uri, NULL, NULL);
if(uri)
{
file = true;
}
else
{
CV_WARN("GStreamer: Error opening file\n");
close();
return false;
}
}
else
{
GError *err = NULL;
uridecodebin = gst_parse_launch(filename, &err);
if(!uridecodebin)
{
fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message);
return false;
}
stream = true;
manualpipeline = true;
}
} else {
stream = true;
uri = g_strdup(filename);
}
bool element_from_uri = false;
if(!uridecodebin)
{
// At this writing, the v4l2 element (and maybe others too) does not support caps renegotiation.
// This means that we cannot use an uridecodebin when dealing with v4l2, since setting
// capture properties will not work.
// The solution (probably only until gstreamer 1.2) is to make an element from uri when dealing with v4l2.
gchar * protocol = gst_uri_get_protocol(uri);
if (!strcasecmp(protocol , "v4l2"))
{
#if GST_VERSION_MAJOR == 0
uridecodebin = gst_element_make_from_uri(GST_URI_SRC, uri, "src");
#else
uridecodebin = gst_element_make_from_uri(GST_URI_SRC, uri, "src", NULL);
#endif
element_from_uri = true;
}else{
uridecodebin = gst_element_factory_make("uridecodebin", NULL);
g_object_set(G_OBJECT(uridecodebin), "uri", uri, NULL);
}
g_free(protocol);
if(!uridecodebin) {
//fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message);
close();
return false;
}
}
if(manualpipeline)
{
GstIterator *it = NULL;
#if GST_VERSION_MAJOR == 0
it = gst_bin_iterate_sinks(GST_BIN(uridecodebin));
if(gst_iterator_next(it, (gpointer *)&sink) != GST_ITERATOR_OK) {
CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n");
return false;
}
#else
it = gst_bin_iterate_sinks (GST_BIN(uridecodebin));
gboolean done = FALSE;
GstElement *element = NULL;
gchar* name = NULL;
GValue value = G_VALUE_INIT;
while (!done) {
switch (gst_iterator_next (it, &value)) {
case GST_ITERATOR_OK:
element = GST_ELEMENT (g_value_get_object (&value));
name = gst_element_get_name(element);
if (name){
if(strstr(name, "opencvsink") != NULL || strstr(name, "appsink") != NULL) {
sink = GST_ELEMENT ( gst_object_ref (element) );
done = TRUE;
}
g_free(name);
}
g_value_unset (&value);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (it);
break;
case GST_ITERATOR_ERROR:
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free (it);
if (!sink){
CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n");
return false;
}
#endif
pipeline = uridecodebin;
}
else
{
pipeline = gst_pipeline_new(NULL);
// videoconvert (in 0.10: ffmpegcolorspace, in 1.x autovideoconvert)
//automatically selects the correct colorspace conversion based on caps.
color = gst_element_factory_make(COLOR_ELEM, NULL);
sink = gst_element_factory_make("appsink", NULL);
gst_bin_add_many(GST_BIN(pipeline), uridecodebin, color, sink, NULL);
if(element_from_uri) {
if(!gst_element_link(uridecodebin, color)) {
CV_ERROR(CV_StsError, "GStreamer: cannot link color -> sink\n");
gst_object_unref(pipeline);
pipeline = NULL;
return false;
}
}else{
g_signal_connect(uridecodebin, "pad-added", G_CALLBACK(newPad), color);
}
if(!gst_element_link(color, sink)) {
CV_ERROR(CV_StsError, "GStreamer: cannot link color -> sink\n");
gst_object_unref(pipeline);
pipeline = NULL;
return false;
}
}
//TODO: is 1 single buffer really high enough?
gst_app_sink_set_max_buffers (GST_APP_SINK(sink), 1);
gst_app_sink_set_drop (GST_APP_SINK(sink), stream);
//do not emit signals: all calls will be synchronous and blocking
gst_app_sink_set_emit_signals (GST_APP_SINK(sink), 0);
#if GST_VERSION_MAJOR == 0
caps = gst_caps_new_simple("video/x-raw-rgb",
"bpp", G_TYPE_INT, 24,
"red_mask", G_TYPE_INT, 0x0000FF,
"green_mask", G_TYPE_INT, 0x00FF00,
"blue_mask", G_TYPE_INT, 0xFF0000,
NULL);
#else
// support 1 and 3 channel 8 bit data, as well as bayer (also 1 channel, 8bit)
caps = gst_caps_from_string("video/x-raw, format=(string){BGR, GRAY8}; video/x-bayer,format=(string){rggb,bggr,grbg,gbrg}");
#endif
gst_app_sink_set_caps(GST_APP_SINK(sink), caps);
gst_caps_unref(caps);
// For video files only: set pipeline to PAUSED state to get its duration
if (file)
{
status = gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PAUSED);
if (status == GST_STATE_CHANGE_ASYNC)
{
// wait for status update
GstState st1;
GstState st2;
status = gst_element_get_state(pipeline, &st1, &st2, GST_CLOCK_TIME_NONE);
}
if (status == GST_STATE_CHANGE_FAILURE)
{
handleMessage(pipeline);
gst_object_unref(pipeline);
pipeline = NULL;
CV_ERROR(CV_StsError, "GStreamer: unable to start pipeline\n");
return false;
}
GstFormat format;
format = GST_FORMAT_DEFAULT;
#if GST_VERSION_MAJOR == 0
if(!gst_element_query_duration(sink, &format, &duration))
#else
if(!gst_element_query_duration(sink, format, &duration))
#endif
{
handleMessage(pipeline);
CV_WARN("GStreamer: unable to query duration of stream");
duration = -1;
}
GstPad* pad = gst_element_get_static_pad(color, "src");
#if GST_VERSION_MAJOR == 0
GstCaps* buffer_caps = gst_pad_get_caps(pad);
#else
GstCaps* buffer_caps = gst_pad_get_current_caps(pad);
#endif
const GstStructure *structure = gst_caps_get_structure (buffer_caps, 0);
if (!gst_structure_get_int (structure, "width", &width))
{
CV_WARN("Cannot query video width\n");
}
if (!gst_structure_get_int (structure, "height", &height))
{
CV_WARN("Cannot query video heigth\n");
}
gint num = 0, denom=1;
if(!gst_structure_get_fraction(structure, "framerate", &num, &denom))
{
CV_WARN("Cannot query video fps\n");
}
fps = (double)num/(double)denom;
// GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline");
}
else
{
duration = -1;
width = -1;
height = -1;
fps = -1;
}
__END__;
return true;
}