diff options
author | Sjoerd Simons <sjoerd@luon.net> | 2008-06-04 17:39:31 +0000 |
---|---|---|
committer | Sebastian Dröge <slomo@circular-chaos.org> | 2008-06-04 17:39:31 +0000 |
commit | 22940c001029de2f55d8b70365bf5eb9c2c368dd (patch) | |
tree | 248f1a19e861cbade8081c631cd0dcd2c171449d /sys/v4l2/gstv4l2src.c | |
parent | f1c5dc21b438ebfe116bd0b35caa098424fdca9f (diff) |
sys/v4l2/gstv4l2src.c: Provide a custom negotiation function to make sure to pick the highest possible framerate and ...
Original commit message from CVS:
Patch by: Sjoerd Simons <sjoerd at luon dot net>
* sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
(gst_v4l2src_fixate), (gst_v4l2src_negotiate):
Provide a custom negotiation function to make sure to pick the highest
possible framerate and resolution. Fixes bug #536646.
Diffstat (limited to 'sys/v4l2/gstv4l2src.c')
-rw-r--r-- | sys/v4l2/gstv4l2src.c | 131 |
1 files changed, 129 insertions, 2 deletions
diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index a84d58c3..88757400 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -235,18 +235,26 @@ GST_BOILERPLATE_FULL (GstV4l2Src, gst_v4l2src, GstPushSrc, GST_TYPE_PUSH_SRC, gst_v4l2src_init_interfaces); static void gst_v4l2src_dispose (GObject * object); + static void gst_v4l2src_finalize (GstV4l2Src * v4l2src); /* basesrc methods */ static gboolean gst_v4l2src_start (GstBaseSrc * src); + static gboolean gst_v4l2src_stop (GstBaseSrc * src); + static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps); + static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src); + static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query); + static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out); static void gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps); +static gboolean gst_v4l2src_negotiate (GstBaseSrc * basesrc); + static void gst_v4l2src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_v4l2src_get_property (GObject * object, guint prop_id, @@ -258,6 +266,7 @@ static void gst_v4l2src_base_init (gpointer g_class) { GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + GstV4l2SrcClass *gstv4l2src_class = GST_V4L2SRC_CLASS (g_class); gstv4l2src_class->v4l2_class_devices = NULL; @@ -276,7 +285,9 @@ static void gst_v4l2src_class_init (GstV4l2SrcClass * klass) { GObjectClass *gobject_class; + GstBaseSrcClass *basesrc_class; + GstPushSrcClass *pushsrc_class; gobject_class = G_OBJECT_CLASS (klass); @@ -305,6 +316,7 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass) basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop); basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query); basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_v4l2src_fixate); + basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2src_negotiate); pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create); } @@ -406,6 +418,7 @@ static void gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps) { GstStructure *structure; + gint i; GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps); @@ -417,12 +430,13 @@ gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps) /* FIXME such sizes? we usually fixate to something in the 320x200 * range... */ /* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE) - and framerate closer to 15/2 that is common in web-cams */ + and the maximum framerate resolution for that size */ gst_structure_fixate_field_nearest_int (structure, "width", GST_V4L2_MAX_SIZE); gst_structure_fixate_field_nearest_int (structure, "height", GST_V4L2_MAX_SIZE); - gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2); + gst_structure_fixate_field_nearest_fraction (structure, "framerate", + G_MAXINT, 1); v = gst_structure_get_value (structure, "format"); if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) { @@ -434,8 +448,99 @@ gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps) gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL); } } + + GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps); } + +static gboolean +gst_v4l2src_negotiate (GstBaseSrc * basesrc) +{ + GstCaps *thiscaps; + + GstCaps *caps = NULL; + + GstCaps *peercaps = NULL; + + gboolean result = FALSE; + + /* first see what is possible on our source pad */ + thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc)); + GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps); + /* nothing or anything is allowed, we're done */ + if (thiscaps == NULL || gst_caps_is_any (thiscaps)) + goto no_nego_needed; + + /* get the peer caps */ + peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc)); + GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps); + if (peercaps && !gst_caps_is_any (peercaps)) { + GstCaps *icaps; + + int i; + + /* Prefer the first caps we are compatible with that the peer proposed */ + for (i = 0; i < gst_caps_get_size (peercaps); i++) { + /* get intersection */ + GstCaps *ipcaps = gst_caps_copy_nth (peercaps, i); + + GST_DEBUG_OBJECT (basesrc, "peer: %" GST_PTR_FORMAT, ipcaps); + + icaps = gst_caps_intersect (thiscaps, ipcaps); + gst_caps_unref (ipcaps); + + if (!gst_caps_is_empty (icaps)) + break; + + gst_caps_unref (icaps); + icaps = NULL; + } + + GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, icaps); + gst_caps_unref (thiscaps); + gst_caps_unref (peercaps); + if (icaps) { + /* take first (and best, since they are sorted) possibility */ + caps = gst_caps_copy_nth (icaps, 0); + gst_caps_unref (icaps); + } + } else { + /* no peer or peer have ANY caps, work with our own caps then */ + caps = thiscaps; + } + if (caps) { + caps = gst_caps_make_writable (caps); + gst_caps_truncate (caps); + + /* now fixate */ + if (!gst_caps_is_empty (caps)) { + gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps); + GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps); + + if (gst_caps_is_any (caps)) { + /* hmm, still anything, so element can do anything and + * nego is not needed */ + result = TRUE; + } else if (gst_caps_is_fixed (caps)) { + /* yay, fixed caps, use those then */ + gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps); + result = TRUE; + } + } + gst_caps_unref (caps); + } + return result; + +no_nego_needed: + { + GST_DEBUG_OBJECT (basesrc, "no negotiation needed"); + if (thiscaps) + gst_caps_unref (thiscaps); + return TRUE; + } +} + + static GstStructure * gst_v4l2src_v4l2fourcc_to_structure (guint32 fourcc) { @@ -465,7 +570,9 @@ gst_v4l2src_v4l2fourcc_to_structure (guint32 fourcc) case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32:{ guint depth = 0, bpp = 0; + gint endianness = 0; + guint32 r_mask = 0, b_mask = 0, g_mask = 0; switch (fourcc) { @@ -622,6 +729,7 @@ static struct v4l2_fmtdesc * gst_v4l2src_get_format_from_fourcc (GstV4l2Src * v4l2src, guint32 fourcc) { struct v4l2_fmtdesc *fmt; + GSList *walk; if (fourcc == 0) @@ -651,6 +759,7 @@ gst_v4l2src_get_all_caps (void) if (caps == NULL) { GstStructure *structure; + guint i; caps = gst_caps_new_empty (); @@ -673,7 +782,9 @@ static GstCaps * gst_v4l2src_get_caps (GstBaseSrc * src) { GstV4l2Src *v4l2src = GST_V4L2SRC (src); + GstCaps *ret; + GSList *walk; if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) { @@ -693,6 +804,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src) for (walk = v4l2src->formats; walk; walk = walk->next) { struct v4l2_fmtdesc *format; + GstStructure *template; format = (struct v4l2_fmtdesc *) walk->data; @@ -733,9 +845,13 @@ gst_v4l2_get_caps_info (GstV4l2Src * v4l2src, GstCaps * caps, guint * fps_d, guint * size) { GstStructure *structure; + const GValue *framerate; + guint32 fourcc; + const gchar *mimetype; + guint outsize; /* default unknown values */ @@ -854,9 +970,13 @@ static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps) { GstV4l2Src *v4l2src; + gint w = 0, h = 0; + struct v4l2_fmtdesc *format; + guint fps_n, fps_d; + guint size; v4l2src = GST_V4L2SRC (src); @@ -906,6 +1026,7 @@ static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query) { GstV4l2Src *src; + gboolean res = FALSE; src = GST_V4L2SRC (bsrc); @@ -997,6 +1118,7 @@ static GstFlowReturn gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf) { gint amount; + gint buffersize; buffersize = v4l2src->frame_byte_size; @@ -1025,6 +1147,7 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf) /* timestamps, LOCK to get clock and base time. */ { GstClock *clock; + GstClockTime timestamp; GST_OBJECT_LOCK (v4l2src); @@ -1076,8 +1199,11 @@ static GstFlowReturn gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf) { GstBuffer *temp; + GstFlowReturn ret; + guint size; + guint count; count = 0; @@ -1121,6 +1247,7 @@ static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf) { GstV4l2Src *v4l2src = GST_V4L2SRC (src); + GstFlowReturn ret; if (v4l2src->use_mmap) { |