From 6dd1750d19ae87446c41f894c1b38bedcf42bbf1 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 15 Jan 2002 15:52:09 +0000 Subject: [PATCH] Updated all plugins to new capsnego format and added some small usability enhancements to v4lelement Original commit message from CVS: Updated all plugins to new capsnego format and added some small usability enhancements to v4lelement --- sys/v4l/gstv4lelement.c | 30 ++- sys/v4l/gstv4lelement.h | 3 + sys/v4l/gstv4lmjpegsink.c | 102 ++++---- sys/v4l/gstv4lmjpegsrc.c | 101 ++++---- sys/v4l/gstv4lmjpegsrc.h | 5 +- sys/v4l/gstv4lsrc.c | 493 +++++++++++++++++++++++--------------- sys/v4l/gstv4lsrc.h | 6 +- sys/v4l/v4l_calls.c | 45 ++-- sys/v4l/v4lsrc_calls.c | 2 +- 9 files changed, 464 insertions(+), 323 deletions(-) diff --git a/sys/v4l/gstv4lelement.c b/sys/v4l/gstv4lelement.c index b2930aabe0..930ba5f772 100644 --- a/sys/v4l/gstv4lelement.c +++ b/sys/v4l/gstv4lelement.c @@ -39,7 +39,9 @@ enum { enum { ARG_0, ARG_CHANNEL, + ARG_CHANNEL_NAME, ARG_NORM, + ARG_NORM_NAME, ARG_HAS_TUNER, ARG_FREQUENCY, ARG_HAS_AUDIO, @@ -119,9 +121,15 @@ gst_v4lelement_class_init (GstV4lElementClass *klass) g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNEL, g_param_spec_int("channel","channel","channel", G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNEL_NAME, + g_param_spec_string("channel_name","channel_name","channel_name", + NULL, G_PARAM_READABLE)); g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM, g_param_spec_int("norm","norm","norm", G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM_NAME, + g_param_spec_string("norm_name","norm_name","norm_name", + NULL, G_PARAM_READABLE)); g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_TUNER, g_param_spec_boolean("has_tuner","has_tuner","has_tuner", @@ -159,10 +167,9 @@ gst_v4lelement_class_init (GstV4lElementClass *klass) g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE, g_param_spec_string("device","device","device", NULL, G_PARAM_READWRITE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_NAME, g_param_spec_string("device_name","device_name","device_name", - NULL, G_PARAM_READWRITE)); + NULL, G_PARAM_READABLE)); g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_IS_CAPTURE, g_param_spec_boolean("can_capture","can_capture","can_capture", @@ -326,7 +333,7 @@ gst_v4lelement_set_property (GObject *object, v4lelement->videodev = g_strdup(g_value_get_string(value)); break; default: - //G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -353,11 +360,26 @@ gst_v4lelement_get_property (GObject *object, gst_v4l_get_chan_norm(v4lelement, &temp_i, NULL); g_value_set_int(value, temp_i); break; + case ARG_CHANNEL_NAME: + if (GST_V4L_IS_OPEN(v4lelement)) + g_value_set_string(value, g_strdup(v4lelement->vchan.name)); + else + g_value_set_string(value, g_strdup("Unknown")); + break; case ARG_NORM: if (GST_V4L_IS_OPEN(v4lelement)) gst_v4l_get_chan_norm(v4lelement, NULL, &temp_i); g_value_set_int(value, temp_i); break; + case ARG_NORM_NAME: + if (GST_V4L_IS_OPEN(v4lelement)) + { + gst_v4l_get_chan_norm(v4lelement, NULL, &temp_i); + g_value_set_string(value, g_strdup(norm_name[temp_i])); + } + else + g_value_set_string(value, g_strdup("Unknwon")); + break; case ARG_HAS_TUNER: g_value_set_boolean(value, FALSE); if (GST_V4L_IS_OPEN(v4lelement)) @@ -454,7 +476,7 @@ gst_v4lelement_get_property (GObject *object, g_value_set_boolean(value, v4lelement->vcap.type & VID_TYPE_MPEG_DECODER); break; default: - //G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } diff --git a/sys/v4l/gstv4lelement.h b/sys/v4l/gstv4lelement.h index b49ebad105..276bb49181 100644 --- a/sys/v4l/gstv4lelement.h +++ b/sys/v4l/gstv4lelement.h @@ -58,6 +58,9 @@ struct _GstV4lElement { /* the video-device's capabilities */ struct video_capability vcap; + /* some more info about the current input's capabilities */ + struct video_channel vchan; + /* caching values */ gint channel; gint norm; diff --git a/sys/v4l/gstv4lmjpegsink.c b/sys/v4l/gstv4lmjpegsink.c index f02a162b78..7c5e3992d3 100644 --- a/sys/v4l/gstv4lmjpegsink.c +++ b/sys/v4l/gstv4lmjpegsink.c @@ -46,24 +46,14 @@ enum { ARG_FRAME_TIME, }; -GST_PADTEMPLATE_FACTORY (sink_template, - "sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_CAPS_NEW ( - "v4lmjpegsink_caps", - "video/jpeg", - "width", GST_PROPS_INT_RANGE (0, G_MAXINT), - "height", GST_PROPS_INT_RANGE (0, G_MAXINT) - ) -) - /* init functions */ static void gst_v4lmjpegsink_class_init (GstV4lMjpegSinkClass *klass); static void gst_v4lmjpegsink_init (GstV4lMjpegSink *v4lmjpegsink); /* the chain of buffers */ +static GstPadConnectReturn gst_v4lmjpegsink_sinkconnect (GstPad *pad, + GstCaps *vscapslist); static void gst_v4lmjpegsink_chain (GstPad *pad, GstBuffer *buf); @@ -79,6 +69,10 @@ static void gst_v4lmjpegsink_get_property (GObject static void gst_v4lmjpegsink_close (GstV4lMjpegSink *v4lmjpegsink); static GstElementStateReturn gst_v4lmjpegsink_change_state (GstElement *element); + +static GstCaps *capslist = NULL; +static GstPadTemplate *sink_template; + static GstElementClass *parent_class = NULL; static guint gst_v4lmjpegsink_signals[LAST_SIGNAL] = { 0 }; @@ -155,37 +149,13 @@ gst_v4lmjpegsink_class_init (GstV4lMjpegSinkClass *klass) gstelement_class->change_state = gst_v4lmjpegsink_change_state; } -static GstPadConnectReturn -gst_v4lmjpegsink_sinkconnect (GstPad *pad, - GstCaps *caps) -{ - GstV4lMjpegSink *v4lmjpegsink; - - v4lmjpegsink = GST_V4LMJPEGSINK (gst_pad_get_parent (pad)); - - if (!GST_CAPS_IS_FIXED (caps)) - return GST_PAD_CONNECT_DELAYED; - - v4lmjpegsink->width = gst_caps_get_int (caps, "width"); - v4lmjpegsink->height = gst_caps_get_int (caps, "height"); - - gst_v4lmjpegsink_set_playback(v4lmjpegsink, - v4lmjpegsink->width, v4lmjpegsink->height, - v4lmjpegsink->x_offset, v4lmjpegsink->y_offset, - GST_V4LELEMENT(v4lmjpegsink)->norm, 0); /* TODO: interlacing */ - - g_signal_emit (G_OBJECT (v4lmjpegsink), gst_v4lmjpegsink_signals[SIGNAL_HAVE_SIZE], 0, - v4lmjpegsink->width, v4lmjpegsink->height); - - return GST_PAD_CONNECT_OK; -} - static void gst_v4lmjpegsink_init (GstV4lMjpegSink *v4lmjpegsink) { - v4lmjpegsink->sinkpad = gst_pad_new_from_template(GST_PADTEMPLATE_GET (sink_template), "sink"); + v4lmjpegsink->sinkpad = gst_pad_new_from_template (sink_template, "sink"); gst_element_add_pad (GST_ELEMENT (v4lmjpegsink), v4lmjpegsink->sinkpad); + gst_pad_set_chain_function (v4lmjpegsink->sinkpad, gst_v4lmjpegsink_chain); gst_pad_set_connect_function (v4lmjpegsink->sinkpad, gst_v4lmjpegsink_sinkconnect); @@ -205,6 +175,39 @@ gst_v4lmjpegsink_init (GstV4lMjpegSink *v4lmjpegsink) } +static GstPadConnectReturn +gst_v4lmjpegsink_sinkconnect (GstPad *pad, + GstCaps *vscapslist) +{ + GstV4lMjpegSink *v4lmjpegsink; + GstCaps *caps; + + v4lmjpegsink = GST_V4LMJPEGSINK (gst_pad_get_parent (pad)); + + for (caps = capslist; caps != NULL; caps = vscapslist = vscapslist->next) + { + v4lmjpegsink->width = gst_caps_get_int (caps, "width"); + v4lmjpegsink->height = gst_caps_get_int (caps, "height"); + + if (!gst_v4lmjpegsink_set_playback(v4lmjpegsink, + v4lmjpegsink->width, v4lmjpegsink->height, + v4lmjpegsink->x_offset, v4lmjpegsink->y_offset, + GST_V4LELEMENT(v4lmjpegsink)->norm, 0)) /* TODO: interlacing */ + continue; + + g_signal_emit (G_OBJECT (v4lmjpegsink), gst_v4lmjpegsink_signals[SIGNAL_HAVE_SIZE], 0, + v4lmjpegsink->width, v4lmjpegsink->height); + + return GST_PAD_CONNECT_OK; + } + + /* if we got here - it's not good */ + gst_element_error(GST_ELEMENT(v4lmjpegsink), + "Failed to find acceptable caps"); + return GST_PAD_CONNECT_REFUSED; +} + + static void gst_v4lmjpegsink_chain (GstPad *pad, GstBuffer *buf) @@ -281,7 +284,7 @@ gst_v4lmjpegsink_set_property (GObject *object, v4lmjpegsink->y_offset = g_value_get_int(value); break; default: - /*parent_class->set_property(object, prop_id, value, pspec);*/ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -312,7 +315,7 @@ gst_v4lmjpegsink_get_property (GObject *object, g_value_set_int (value, v4lmjpegsink->bufsize); break; default: - /*parent_class->get_property(object, prop_id, value, pspec);*/ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -379,14 +382,29 @@ plugin_init (GModule *module, GstPlugin *plugin) { GstElementFactory *factory; + GstCaps *caps; /* create an elementfactory for the v4lmjpegsink element */ factory = gst_elementfactory_new("v4lmjpegsink",GST_TYPE_V4LMJPEGSINK, &gst_v4lmjpegsink_details); g_return_val_if_fail(factory != NULL, FALSE); - gst_elementfactory_add_padtemplate (factory, - GST_PADTEMPLATE_GET (sink_template)); + caps = gst_caps_new ("v4lmjpegsink_caps", + "video/jpeg", + gst_props_new ( + "width", GST_PROPS_INT_RANGE (0, G_MAXINT), + "height", GST_PROPS_INT_RANGE (0, G_MAXINT), + NULL ) + ); + capslist = gst_caps_append(capslist, caps); + + sink_template = gst_padtemplate_new ( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + capslist, NULL); + + gst_elementfactory_add_padtemplate (factory, sink_template); gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); diff --git a/sys/v4l/gstv4lmjpegsrc.c b/sys/v4l/gstv4lmjpegsrc.c index 88f9cc5e26..ee7977550a 100644 --- a/sys/v4l/gstv4lmjpegsrc.c +++ b/sys/v4l/gstv4lmjpegsrc.c @@ -57,12 +57,8 @@ static void gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass * static void gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc); /* pad/buffer functions */ -/* -static GstPadNegotiateReturn gst_v4lmjpegsrc_negotiate (GstPad *pad, - GstCaps **caps, - gpointer *user_data); - */ -static GstCaps* gst_v4lmjpegsrc_create_caps (GstV4lMjpegSrc *v4lmjpegsrc); +static GstPadConnectReturn gst_v4lmjpegsrc_srcconnect (GstPad *pad, + GstCaps *caps); static GstBuffer* gst_v4lmjpegsrc_get (GstPad *pad); /* get/set params */ @@ -87,6 +83,9 @@ static GstBuffer* gst_v4lmjpegsrc_buffer_copy (GstBuffer *srcbu static void gst_v4lmjpegsrc_buffer_free (GstBuffer *buf); +static GstCaps *capslist = NULL; +static GstPadTemplate *src_template; + static GstElementClass *parent_class = NULL; //static guint gst_v4lmjpegsrc_signals[LAST_SIGNAL] = { 0 }; @@ -174,11 +173,11 @@ gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass *klass) static void gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc) { - v4lmjpegsrc->srcpad = gst_pad_new("src", GST_PAD_SRC); + v4lmjpegsrc->srcpad = gst_pad_new_from_template (src_template, "src"); gst_element_add_pad(GST_ELEMENT(v4lmjpegsrc), v4lmjpegsrc->srcpad); gst_pad_set_get_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get); - //gst_pad_set_negotiate_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_negotiate); + gst_pad_set_connect_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_srcconnect); v4lmjpegsrc->bufferpool = gst_buffer_pool_new(); gst_buffer_pool_set_buffer_new_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_new); @@ -202,46 +201,21 @@ gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc) v4lmjpegsrc->numbufs = 64; v4lmjpegsrc->bufsize = 256; - v4lmjpegsrc->init = TRUE; + v4lmjpegsrc->capslist = capslist; } - -/* -static GstPadNegotiateReturn -gst_v4lmjpegsrc_negotiate (GstPad *pad, - GstCaps **caps, - gpointer *user_data) +static GstPadConnectReturn +gst_v4lmjpegsrc_srcconnect (GstPad *pad, + GstCaps *caps) { GstV4lMjpegSrc *v4lmjpegsrc; v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad)); - if (!*caps) { - return GST_PAD_NEGOTIATE_FAIL; - } - else { - return GST_PAD_NEGOTIATE_AGREE; - } + /* we will try_set_caps() with the actual size (wxh) when we know it */ - return GST_PAD_NEGOTIATE_FAIL; -} -*/ - - -static GstCaps* -gst_v4lmjpegsrc_create_caps (GstV4lMjpegSrc *v4lmjpegsrc) -{ - GstCaps *caps; - - caps = GST_CAPS_NEW ( - "v4lmjpegsrc_caps", - "video/jpeg", - "width", GST_PROPS_INT(v4lmjpegsrc->end_width), - "height", GST_PROPS_INT(v4lmjpegsrc->end_height) - ); - - return caps; + return GST_PAD_CONNECT_OK; } @@ -256,17 +230,6 @@ gst_v4lmjpegsrc_get (GstPad *pad) v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad)); - if (v4lmjpegsrc->init) { - gst_pad_try_set_caps (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_create_caps (v4lmjpegsrc)); - v4lmjpegsrc->init = FALSE; - } - else { - if (!gst_pad_get_caps (v4lmjpegsrc->srcpad) && - !gst_pad_renegotiate (v4lmjpegsrc->srcpad)) { - return NULL; - } - } - buf = gst_buffer_new_from_pool(v4lmjpegsrc->bufferpool, 0, 0); if (!buf) { @@ -326,7 +289,7 @@ gst_v4lmjpegsrc_set_property (GObject *object, v4lmjpegsrc->bufsize = g_value_get_int(value); break; default: - /*parent_class->set_property(object, prop_id, value, pspec);*/ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -357,7 +320,7 @@ gst_v4lmjpegsrc_get_property (GObject *object, g_value_set_int(value, v4lmjpegsrc->breq.size); break; default: - /*parent_class->get_property(object, prop_id, value, pspec);*/ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -368,6 +331,7 @@ gst_v4lmjpegsrc_change_state (GstElement *element) { GstV4lMjpegSrc *v4lmjpegsrc; GstElementStateReturn parent_value; + GstCaps *caps; g_return_val_if_fail(GST_IS_V4LMJPEGSRC(element), GST_STATE_FAILURE); @@ -396,7 +360,19 @@ gst_v4lmjpegsrc_change_state (GstElement *element) v4lmjpegsrc->quality)) return GST_STATE_FAILURE; } - v4lmjpegsrc->init = TRUE; + /* we now have an actual width/height - *set it* */ + caps = gst_caps_new("v4lmjpegsrc_caps", + "video/jpeg", + gst_props_new( + "width", GST_PROPS_INT(v4lmjpegsrc->end_width), + "height", GST_PROPS_INT(v4lmjpegsrc->end_height), + NULL ) ); + if (!gst_pad_try_set_caps(v4lmjpegsrc->srcpad, caps)) + { + gst_element_error(GST_ELEMENT(v4lmjpegsrc), + "Failed to set new caps"); + return GST_STATE_FAILURE; + } if (!gst_v4lmjpegsrc_capture_init(v4lmjpegsrc)) return GST_STATE_FAILURE; break; @@ -509,11 +485,30 @@ static gboolean plugin_init (GModule *module, GstPlugin *plugin) { GstElementFactory *factory; + GstCaps *caps; /* create an elementfactory for the v4lmjpegsrcparse element */ factory = gst_elementfactory_new("v4lmjpegsrc",GST_TYPE_V4LMJPEGSRC, &gst_v4lmjpegsrc_details); g_return_val_if_fail(factory != NULL, FALSE); + + caps = gst_caps_new ("v4lmjpegsrc_caps", + "video/jpeg", + gst_props_new ( + "width", GST_PROPS_INT_RANGE (0, G_MAXINT), + "height", GST_PROPS_INT_RANGE (0, G_MAXINT), + NULL ) + ); + capslist = gst_caps_append(capslist, caps); + + src_template = gst_padtemplate_new ( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + capslist, NULL); + + gst_elementfactory_add_padtemplate (factory, src_template); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); return TRUE; diff --git a/sys/v4l/gstv4lmjpegsrc.h b/sys/v4l/gstv4lmjpegsrc.h index f250daa208..e77da9b5b0 100644 --- a/sys/v4l/gstv4lmjpegsrc.h +++ b/sys/v4l/gstv4lmjpegsrc.h @@ -55,6 +55,9 @@ struct _GstV4lMjpegSrc { struct mjpeg_sync bsync; struct mjpeg_requestbuffers breq; + /* list of available caps */ + GstCaps *capslist; + /* caching values */ gint x_offset; gint y_offset; @@ -69,8 +72,6 @@ struct _GstV4lMjpegSrc { gint quality; gint numbufs; gint bufsize; /* in KB */ - - gboolean init; }; struct _GstV4lMjpegSrcClass { diff --git a/sys/v4l/gstv4lsrc.c b/sys/v4l/gstv4lsrc.c index a0723a84a3..4eb98745f3 100644 --- a/sys/v4l/gstv4lsrc.c +++ b/sys/v4l/gstv4lsrc.c @@ -54,11 +54,8 @@ static void gst_v4lsrc_class_init (GstV4lSrcClass *klass); static void gst_v4lsrc_init (GstV4lSrc *v4lsrc); /* pad/buffer functions */ -/*static GstPadNegotiateReturn gst_v4lsrc_negotiate (GstPad *pad, - GstCaps **caps, - gpointer *user_data); - */ -static GstCaps* gst_v4lsrc_create_caps (GstV4lSrc *v4lsrc); +static GstPadConnectReturn gst_v4lsrc_srcconnect (GstPad *pad, + GstCaps *caps); static GstBuffer* gst_v4lsrc_get (GstPad *pad); /* get/set params */ @@ -83,6 +80,9 @@ static GstBuffer* gst_v4lsrc_buffer_copy (GstBuffer *srcbuf); static void gst_v4lsrc_buffer_free (GstBuffer *buf); +static GstCaps *capslist = NULL; +static GstPadTemplate *src_template; + static GstElementClass *parent_class = NULL;\ //static guint gst_v4lsrc_signals[LAST_SIGNAL] = { 0 }; @@ -151,11 +151,11 @@ gst_v4lsrc_class_init (GstV4lSrcClass *klass) static void gst_v4lsrc_init (GstV4lSrc *v4lsrc) { - v4lsrc->srcpad = gst_pad_new("src", GST_PAD_SRC); + v4lsrc->srcpad = gst_pad_new_from_template (src_template, "src"); gst_element_add_pad(GST_ELEMENT(v4lsrc), v4lsrc->srcpad); gst_pad_set_get_function (v4lsrc->srcpad, gst_v4lsrc_get); - //gst_pad_set_negotiate_function (v4lsrc->srcpad, gst_v4lsrc_negotiate); + gst_pad_set_connect_function (v4lsrc->srcpad, gst_v4lsrc_srcconnect); v4lsrc->bufferpool = gst_buffer_pool_new(); gst_buffer_pool_set_buffer_new_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_new); @@ -163,192 +163,155 @@ gst_v4lsrc_init (GstV4lSrc *v4lsrc) gst_buffer_pool_set_buffer_free_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_free); gst_buffer_pool_set_user_data(v4lsrc->bufferpool, v4lsrc); - v4lsrc->palette = VIDEO_PALETTE_YUV420P; + v4lsrc->palette = 0; /* means 'any' - user can specify a specific palette */ v4lsrc->width = 160; v4lsrc->height = 120; v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5; - v4lsrc->init = TRUE; + v4lsrc->capslist = capslist; } -#if 0 -static GstPadNegotiateReturn -gst_v4lsrc_negotiate (GstPad *pad, - GstCaps **caps, - gpointer *user_data) +static GstPadConnectReturn +gst_v4lsrc_srcconnect (GstPad *pad, + GstCaps *vscapslist) { GstV4lSrc *v4lsrc; + GstCaps *caps, *newcaps; + gint palette = v4lsrc->palette; v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad)); - if (!*caps) { - return GST_PAD_NEGOTIATE_FAIL; - } - else { - gint width, height; - gulong format; - - width = gst_caps_get_int (*caps, "width"); - height = gst_caps_get_int (*caps, "height"); - format = gst_caps_get_fourcc_int (*caps, "format"); - - switch (format) { - case GST_MAKE_FOURCC ('R','G','B',' '): + /* TODO: caps = gst_caps_normalize(capslist); */ + for (caps = vscapslist ; caps != NULL ; caps = vscapslist = vscapslist->next) + { + if (v4lsrc->palette > 0) + { + switch (v4lsrc->palette) { - gint depth; - - depth = gst_caps_get_int (*caps, "depth"); - - switch (depth) { - case 15: - v4lsrc->palette = VIDEO_PALETTE_RGB555; - v4lsrc->buffer_size = width * height * 2; - break; - case 16: - v4lsrc->palette = VIDEO_PALETTE_RGB565; - v4lsrc->buffer_size = width * height * 2; - break; - case 24: - v4lsrc->palette = VIDEO_PALETTE_RGB24; - v4lsrc->buffer_size = width * height * 3; - break; - case 32: - v4lsrc->palette = VIDEO_PALETTE_RGB32; - v4lsrc->buffer_size = width * height * 4; - break; - default: - *caps = NULL; - return GST_PAD_NEGOTIATE_TRY; - } - - break; - } - - case GST_MAKE_FOURCC ('I','4','2','0'): - v4lsrc->palette = VIDEO_PALETTE_YUV420P; - v4lsrc->buffer_size = width * height * 1.5; - break; - - case GST_MAKE_FOURCC ('U','Y','V','Y'): - v4lsrc->palette = VIDEO_PALETTE_UYVY; //YUV422?; - v4lsrc->buffer_size = width * height * 2; - break; - - case GST_MAKE_FOURCC ('Y','U','Y','2'): - v4lsrc->palette = VIDEO_PALETTE_YUYV; //YUV422?; - v4lsrc->buffer_size = width * height * 2; - break; - - /* TODO: add YUV4:2:2 planar and YUV4:2:0 packed, maybe also YUV4:1:1? */ - - default: - *caps = NULL; - return GST_PAD_NEGOTIATE_TRY; - - } - - /* if we get here, it's okay */ - v4lsrc->width = width; - v4lsrc->height = height; - - return GST_PAD_NEGOTIATE_AGREE; - } - - return GST_PAD_NEGOTIATE_FAIL; -} -#endif - - -static GstCaps* -gst_v4lsrc_create_caps (GstV4lSrc *v4lsrc) -{ - GstCaps *caps = NULL; - gulong fourcc = 0; - - switch (v4lsrc->palette) { - case VIDEO_PALETTE_RGB555: - case VIDEO_PALETTE_RGB565: - case VIDEO_PALETTE_RGB24: - case VIDEO_PALETTE_RGB32: - { - int depth=0, bpp=0; - - fourcc = GST_STR_FOURCC ("RGB "); - - switch (v4lsrc->palette) { - case VIDEO_PALETTE_RGB555: - depth = 15; - bpp = 2; - break; - case VIDEO_PALETTE_RGB565: - depth = 16; - bpp = 2; - break; - case VIDEO_PALETTE_RGB24: - depth = 24; - bpp = 3; - break; - case VIDEO_PALETTE_RGB32: - depth = 32; - bpp = 4; - break; - } - - caps = GST_CAPS_NEW ( - "v4lsrc_caps", - "video/raw", - "format", GST_PROPS_FOURCC (fourcc), - "width", GST_PROPS_INT (v4lsrc->width), - "height", GST_PROPS_INT (v4lsrc->height), - "bpp", GST_PROPS_INT (bpp), - "depth", GST_PROPS_INT (depth) - ); - - v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * bpp; - - break; - } - - case VIDEO_PALETTE_YUV422: - case VIDEO_PALETTE_YUV420P: - { - switch (v4lsrc->palette) { - case VIDEO_PALETTE_YUV422: - fourcc = (G_BYTE_ORDER == G_BIG_ENDIAN) ? - GST_STR_FOURCC("UYVY") : GST_STR_FOURCC("YUY2"); - v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2; - break; - case VIDEO_PALETTE_YUYV: - fourcc = GST_STR_FOURCC("YUY2"); - v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2; - break; - case VIDEO_PALETTE_UYVY: - fourcc = GST_STR_FOURCC("UYVY"); - v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2; - break; case VIDEO_PALETTE_YUV420P: - fourcc = GST_STR_FOURCC("I420"); - v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5; - break; + if (gst_caps_get_fourcc_int (caps, "format") != GST_MAKE_FOURCC('I','4','2','0') && + gst_caps_get_fourcc_int (caps, "format") != GST_MAKE_FOURCC('I','Y','U','V')) + goto try_next; + goto try_caps; + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUYV: + if (gst_caps_get_fourcc_int (caps, "format") != GST_MAKE_FOURCC('Y','U','Y','2')) + goto try_next; + goto try_caps; + case VIDEO_PALETTE_UYVY: + if (gst_caps_get_fourcc_int (caps, "format") != GST_MAKE_FOURCC('U','Y','V','Y')) + goto try_next; + goto try_caps; + case VIDEO_PALETTE_YUV411: + if (gst_caps_get_fourcc_int (caps, "format") != GST_MAKE_FOURCC('Y','4','1','P')) + goto try_next; + goto try_caps; + case VIDEO_PALETTE_RGB555: + if (gst_caps_get_fourcc_int (caps, "format") != GST_MAKE_FOURCC('R','G','B',' ') || + gst_caps_get_int(caps, "depth") != 15) + goto try_next; + goto try_caps; + case VIDEO_PALETTE_RGB565: + if (gst_caps_get_fourcc_int (caps, "format") != GST_MAKE_FOURCC('R','G','B',' ') || + gst_caps_get_int(caps, "depth") != 16) + goto try_next; + goto try_caps; + case VIDEO_PALETTE_RGB24: + if (gst_caps_get_fourcc_int (caps, "format") != GST_MAKE_FOURCC('R','G','B',' ') || + gst_caps_get_int(caps, "depth") != 24) + goto try_next; + goto try_caps; + case VIDEO_PALETTE_RGB32: + if (gst_caps_get_fourcc_int (caps, "format") != GST_MAKE_FOURCC('R','G','B',' ') || + gst_caps_get_int(caps, "depth") != 32) + goto try_next; + goto try_caps; + default: + goto try_next; + } + } + else + { + switch (gst_caps_get_fourcc_int(caps, "format")) + { + case GST_MAKE_FOURCC('I','4','2','0'): + case GST_MAKE_FOURCC('I','Y','U','V'): + palette = VIDEO_PALETTE_YUV420P; + goto try_caps; + case GST_MAKE_FOURCC('Y','U','Y','2'): + palette = VIDEO_PALETTE_YUV422; + goto try_caps; + case GST_MAKE_FOURCC('U','Y','V','Y'): + palette = VIDEO_PALETTE_UYVY; + goto try_caps; + case GST_MAKE_FOURCC('Y','4','1','P'): + palette = VIDEO_PALETTE_YUV411; + goto try_caps; + case GST_MAKE_FOURCC('R','G','B',' '): + switch (gst_caps_get_int(caps, "depth")) + { + case 15: + palette = VIDEO_PALETTE_RGB555; + goto try_caps; + case 16: + palette = VIDEO_PALETTE_RGB565; + goto try_caps; + case 24: + palette = VIDEO_PALETTE_RGB24; + goto try_caps; + case 32: + palette = VIDEO_PALETTE_RGB32; + goto try_caps; + default: + goto try_next; + } + default: + goto try_next; } - - caps = GST_CAPS_NEW ( - "v4lsrc_caps", - "video/raw", - "format", GST_PROPS_FOURCC (fourcc), - "width", GST_PROPS_INT (v4lsrc->width), - "height", GST_PROPS_INT (v4lsrc->height) - ); - - break; } - default: - return NULL; + /* if this caps wasn't useful, try the next one */ + try_next: + continue; + + /* if this caps was useful, try it out */ + try_caps: + /* TODO: try the current 'palette' out on the video device */ + + if (!gst_v4lsrc_set_capture(v4lsrc, v4lsrc->width, v4lsrc->height, palette)) + continue; + + /* try to connect the pad/caps with the actual width/height */ + if (palette >= VIDEO_PALETTE_RGB565 && palette <= VIDEO_PALETTE_RGB555) + newcaps = gst_caps_new("v4lsrc_caps", + "video/raw", + gst_props_new( + "format", GST_PROPS_FOURCC(gst_caps_get_fourcc_int(caps, "format")), + "width", GST_PROPS_INT(v4lsrc->width), + "width", GST_PROPS_INT(v4lsrc->height), + "bpp", GST_PROPS_INT(gst_caps_get_int(caps, "bpp")), + "depth", GST_PROPS_INT(gst_caps_get_int(caps, "depth")), + NULL ) ); + else + newcaps = gst_caps_new("v4lsrc_caps", + "video/raw", + gst_props_new( + "format", GST_PROPS_FOURCC(gst_caps_get_fourcc_int(caps, "format")), + "width", GST_PROPS_INT(v4lsrc->width), + "height", GST_PROPS_INT(v4lsrc->height), + NULL ) ); + + if (!gst_pad_try_set_caps(v4lsrc->srcpad, newcaps)) + continue; + else + return GST_PAD_CONNECT_DONE; } - return caps; + /* still nothing - no good caps */ + gst_element_error(GST_ELEMENT(v4lsrc), + "Failed to find acceptable caps"); + return GST_PAD_CONNECT_REFUSED; } @@ -363,17 +326,6 @@ gst_v4lsrc_get (GstPad *pad) v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad)); - if (v4lsrc->init) { - gst_pad_try_set_caps (v4lsrc->srcpad, gst_v4lsrc_create_caps (v4lsrc)); - v4lsrc->init = FALSE; - } - else { - if (!gst_pad_get_caps (v4lsrc->srcpad) && - !gst_pad_renegotiate (v4lsrc->srcpad)) { - return NULL; - } - } - buf = gst_buffer_new_from_pool(v4lsrc->bufferpool, 0, 0); if (!buf) { @@ -419,7 +371,7 @@ gst_v4lsrc_set_property (GObject *object, break; default: - /*parent_class->set_property(object, prop_id, value, pspec);*/ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -462,7 +414,7 @@ gst_v4lsrc_get_property (GObject *object, break; default: - /*parent_class->get_property(object, prop_id, value, pspec);*/ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -473,6 +425,7 @@ gst_v4lsrc_change_state (GstElement *element) { GstV4lSrc *v4lsrc; GstElementStateReturn parent_value; + GstCaps *caps; g_return_val_if_fail(GST_IS_V4LSRC(element), GST_STATE_FAILURE); @@ -481,9 +434,120 @@ gst_v4lsrc_change_state (GstElement *element) switch (GST_STATE_TRANSITION(element)) { case GST_STATE_READY_TO_PAUSED: /* set capture parameters and mmap the buffers */ - if (!gst_v4lsrc_set_capture(v4lsrc, v4lsrc->width, v4lsrc->height, v4lsrc->palette)) + if (!gst_v4lsrc_set_capture(v4lsrc, v4lsrc->width, v4lsrc->height, + v4lsrc->palette>0 ? v4lsrc->palette : v4lsrc->mmap.format)) return GST_STATE_FAILURE; - v4lsrc->init = TRUE; + /* retry setting the video-palette */ + if (v4lsrc->palette > 0) + { + switch (v4lsrc->palette) + { + case VIDEO_PALETTE_YUYV: + case VIDEO_PALETTE_UYVY: + case VIDEO_PALETTE_YUV422: + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_YUV411: + { + gulong format; + switch (v4lsrc->palette) + { + case VIDEO_PALETTE_YUYV: + format = GST_MAKE_FOURCC('Y','U','Y','2'); + break; + case VIDEO_PALETTE_UYVY: + format = GST_MAKE_FOURCC('U','Y','V','Y'); + break; + case VIDEO_PALETTE_YUV422: + format = GST_MAKE_FOURCC('Y','U','Y','2'); + break; + case VIDEO_PALETTE_YUV420P: + format = GST_MAKE_FOURCC('I','4','2','0'); + break; + case VIDEO_PALETTE_YUV411: + format = GST_MAKE_FOURCC('Y','4','1','P'); + break; + } + caps = gst_caps_new("v4lsrc_caps", + "video/raw", + gst_props_new( + "format", GST_PROPS_FOURCC(format), + "width", GST_PROPS_INT(v4lsrc->width), + "height", GST_PROPS_INT(v4lsrc->height), + NULL ) ); + break; + } + case VIDEO_PALETTE_RGB555: + case VIDEO_PALETTE_RGB565: + case VIDEO_PALETTE_RGB24: + case VIDEO_PALETTE_RGB32: + { + gint depth, bpp; + switch (v4lsrc->palette) + { + case VIDEO_PALETTE_RGB555: + bpp = 2; + depth = 15; + break; + case VIDEO_PALETTE_RGB565: + bpp = 2; + depth = 16; + break; + case VIDEO_PALETTE_RGB24: + bpp = 3; + depth = 24; + break; + case VIDEO_PALETTE_RGB32: + bpp = 4; + depth = 32; + break; + } + caps = gst_caps_new("v4lsrc_caps", + "video/raw", + gst_props_new( + "format", GST_PROPS_FOURCC(GST_MAKE_FOURCC('R','G','B',' ')), + "width", GST_PROPS_INT(v4lsrc->width), + "height", GST_PROPS_INT(v4lsrc->height), + "bpp", GST_PROPS_INT(bpp), + "depth", GST_PROPS_INT(depth), + NULL ) ); + break; + } + default: + gst_element_error(GST_ELEMENT(v4lsrc), + "Failed to find a fourcc code for palette %d (\'%s\')", + v4lsrc->palette, palette_name[v4lsrc->palette]); + return GST_STATE_FAILURE; + } + } + else + { + GstCaps *oldcaps = gst_pad_get_caps(v4lsrc->srcpad); + + if (gst_caps_get_fourcc_int(oldcaps, "format") == GST_MAKE_FOURCC('R','G','B',' ')) + caps = gst_caps_new("v4lsrc_caps", + "video/raw", + gst_props_new( + "format", GST_PROPS_FOURCC(GST_MAKE_FOURCC('R','G','B',' ')), + "width", GST_PROPS_INT(v4lsrc->width), + "height", GST_PROPS_INT(v4lsrc->height), + "bpp", GST_PROPS_INT(gst_caps_get_int(oldcaps, "bpp")), + "depth", GST_PROPS_INT(gst_caps_get_int(oldcaps, "depth")), + NULL) ); + else + caps = gst_caps_new("v4lsrc_caps", + "video/raw", + gst_props_new( + "format", GST_PROPS_FOURCC(gst_caps_get_fourcc_int(oldcaps, "format")), + "width", GST_PROPS_INT(v4lsrc->width), + "height", GST_PROPS_INT(v4lsrc->height), + NULL) ); + } + if (!gst_pad_try_set_caps(v4lsrc->srcpad, caps)) + { + gst_element_error(GST_ELEMENT(v4lsrc), + "Failed to set new caps"); + return GST_STATE_FAILURE; + } if (!gst_v4lsrc_capture_init(v4lsrc)) return GST_STATE_FAILURE; break; @@ -573,7 +637,7 @@ gst_v4lsrc_buffer_free (GstBuffer *buf) } gst_element_error(GST_ELEMENT(v4lsrc), - "Couldn't find the buffer"); + "Couldn\'t find the buffer"); } @@ -582,11 +646,60 @@ plugin_init (GModule *module, GstPlugin *plugin) { GstElementFactory *factory; + GstCaps *caps; + gint i; + gulong format[5] = { GST_MAKE_FOURCC('Y','U','Y','2'), /* VIDEO_PALETTE_YUV422/_YUYV */ + GST_MAKE_FOURCC('I','4','2','0'), /* VIDEO_PALETTE_YUV420P */ + GST_MAKE_FOURCC('I','Y','U','V'), /* VIDEO_PALETTE_YUV420P */ + GST_MAKE_FOURCC('U','Y','V','Y'), /* VIDEO_PALETTE_UYVY */ + GST_MAKE_FOURCC('Y','4','1','P') /* VIDEO_PALETTE_YUV411 */ + }; + gint rgb_bpp[4] = { 2, 2, 3, 4 }; + gint rgb_depth[4] = { 15, 16, 24, 32 }; /* create an elementfactory for the v4lsrc */ factory = gst_elementfactory_new("v4lsrc",GST_TYPE_V4LSRC, &gst_v4lsrc_details); g_return_val_if_fail(factory != NULL, FALSE); + + /* make a list of all available caps - first the YUV formats */ + for (i=0;i<5;i++) + { + caps = gst_caps_new ("v4lsrc_caps", + "video/raw", + gst_props_new ( + "format", GST_PROPS_FOURCC(format[i]), + "width", GST_PROPS_INT_RANGE (0, G_MAXINT), + "height", GST_PROPS_INT_RANGE (0, G_MAXINT), + NULL ) + ); + capslist = gst_caps_append(capslist, caps); + } + + /* now all the RGB formats */ + for (i=0;i<4;i++) + { + caps = gst_caps_new ("v4lsrc_caps", + "video/raw", + gst_props_new ( + "format", GST_PROPS_FOURCC(GST_MAKE_FOURCC('R','G','B',' ')), + "width", GST_PROPS_INT_RANGE (0, G_MAXINT), + "height", GST_PROPS_INT_RANGE (0, G_MAXINT), + "bpp", GST_PROPS_INT(rgb_bpp[i]), + "depth", GST_PROPS_INT(rgb_depth[i]), + NULL ) + ); + capslist = gst_caps_append(capslist, caps); + } + + src_template = gst_padtemplate_new ( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + capslist, NULL); + + gst_elementfactory_add_padtemplate (factory, src_template); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); return TRUE; diff --git a/sys/v4l/gstv4lsrc.h b/sys/v4l/gstv4lsrc.h index e45ab6f0bc..091227964a 100644 --- a/sys/v4l/gstv4lsrc.h +++ b/sys/v4l/gstv4lsrc.h @@ -49,9 +49,6 @@ struct _GstV4lSrc { /* bufferpool for the buffers we're gonna use */ GstBufferPool *bufferpool; - /* whether we need to reset the GstPad */ - gboolean init; - /* capture/buffer info */ struct video_mmap mmap; struct video_mbuf mbuf; @@ -71,6 +68,9 @@ struct _GstV4lSrc { pthread_mutex_t mutex_queued_frames; pthread_cond_t cond_queued_frames; + /* list of available caps */ + GstCaps *capslist; + /* caching values */ gint width; gint height; diff --git a/sys/v4l/v4l_calls.c b/sys/v4l/v4l_calls.c index c16748cf2b..b2c16ead46 100644 --- a/sys/v4l/v4l_calls.c +++ b/sys/v4l/v4l_calls.c @@ -161,26 +161,16 @@ gst_v4l_get_chan_norm (GstV4lElement *v4lelement, gint *channel, gint *norm) { - struct video_channel vchan; - #ifdef DEBUG fprintf(stderr, "V4L: gst_v4l_get_chan_norm()\n"); #endif GST_V4L_CHECK_OPEN(v4lelement); - if (ioctl(v4lelement->video_fd, VIDIOCGCHAN, &vchan) < 0) - { - gst_element_error(GST_ELEMENT(v4lelement), - "Error getting the channel/norm settings: %s", - sys_errlist[errno]); - return FALSE; - } - if (channel) - *channel = vchan.channel; + *channel = v4lelement->vchan.channel; if (norm) - *norm = vchan.norm; + *norm = v4lelement->vchan.norm; return TRUE; } @@ -198,8 +188,6 @@ gst_v4l_set_chan_norm (GstV4lElement *v4lelement, gint channel, gint norm) { - struct video_channel vchan; - #ifdef DEBUG fprintf(stderr, "V4L: gst_v4l_set_chan_norm(), channel = %d, norm = %d (%s)\n", channel, norm, norm_name[norm]); @@ -208,19 +196,10 @@ gst_v4l_set_chan_norm (GstV4lElement *v4lelement, GST_V4L_CHECK_OPEN(v4lelement); GST_V4L_CHECK_NOT_ACTIVE(v4lelement); -#if 0 - if (ioctl(v4lelement->video_fd, VIDIOCGCHAN, &vchan) < 0) - { - gst_error("V4lElement - Error getting the channel/norm settings: %s", - sys_errlist[errno]); - return FALSE; - } -#endif + v4lelement->vchan.channel = channel; + v4lelement->vchan.norm = norm; - vchan.channel = channel; - vchan.norm = norm; - - if (ioctl(v4lelement->video_fd, VIDIOCSCHAN, &vchan) < 0) + if (ioctl(v4lelement->video_fd, VIDIOCSCHAN, &(v4lelement->vchan)) < 0) { gst_element_error(GST_ELEMENT(v4lelement), "Error setting the channel/norm settings: %s", @@ -228,6 +207,14 @@ gst_v4l_set_chan_norm (GstV4lElement *v4lelement, return FALSE; } + if (ioctl(v4lelement->video_fd, VIDIOCGCHAN, &(v4lelement->vchan)) < 0) + { + gst_element_error(GST_ELEMENT(v4lelement), + "Error getting the channel/norm settings: %s", + sys_errlist[errno]); + return FALSE; + } + return TRUE; } @@ -246,7 +233,8 @@ gst_v4l_has_tuner (GstV4lElement *v4lelement) GST_V4L_CHECK_OPEN(v4lelement); - return (v4lelement->vcap.type & VID_TYPE_TUNER); + return (v4lelement->vcap.type & VID_TYPE_TUNER && + v4lelement->vchan.flags & VIDEO_VC_TUNER); } @@ -442,7 +430,8 @@ gst_v4l_has_audio (GstV4lElement *v4lelement) GST_V4L_CHECK_OPEN(v4lelement); - return (v4lelement->vcap.audios > 0); + return (v4lelement->vcap.audios > 0 && + v4lelement->vchan.flags & VIDEO_VC_AUDIO); } diff --git a/sys/v4l/v4lsrc_calls.c b/sys/v4l/v4lsrc_calls.c index a71eed7070..bc01266567 100644 --- a/sys/v4l/v4lsrc_calls.c +++ b/sys/v4l/v4lsrc_calls.c @@ -240,7 +240,7 @@ gst_v4lsrc_set_capture (GstV4lSrc *v4lsrc, width, height, palette); #endif - GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc)); + /*GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));*/ GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lsrc)); v4lsrc->mmap.width = width;