sys/v4l2/gstv4l2src.c: Provide a custom negotiation function to make sure to pick...
authorSjoerd Simons <sjoerd@luon.net>
Wed, 4 Jun 2008 17:39:31 +0000 (17:39 +0000)
committerSebastian Dröge <slomo@circular-chaos.org>
Wed, 4 Jun 2008 17:39:31 +0000 (17:39 +0000)
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.

ChangeLog
sys/v4l2/gstv4l2src.c

index 69511ef..888ef23 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2008-06-04  Sebastian Dröge  <slomo@circular-chaos.org>
+
+       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.
+
 2008-06-04  Thijs Vermeir  <thijsvermeir@gmail.com>
 
        * gst/avi/gstavidemux.c:
index a84d58c..8875740 100644 (file)
@@ -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) {