negotiating webcam framerate now works
authorThomas Vander Stichele <thomas@apestaart.org>
Wed, 9 Jun 2004 11:32:39 +0000 (11:32 +0000)
committerThomas Vander Stichele <thomas@apestaart.org>
Wed, 9 Jun 2004 11:32:39 +0000 (11:32 +0000)
Original commit message from CVS:
negotiating webcam framerate now works

ChangeLog
sys/v4l/gstv4lsrc.c
sys/v4l/v4l_calls.c

index 22d26de..e69a658 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2004-06-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+       * sys/v4l/gstv4lsrc.c: (gst_v4lsrc_get_fps_list),
+       (gst_v4lsrc_get_fps), (gst_v4lsrc_srcconnect),
+       (gst_v4lsrc_getcaps):
+       * sys/v4l/v4l_calls.c: (gst_v4l_set_window_properties),
+       (gst_v4l_get_picture), (gst_v4l_get_audio), (gst_v4l_set_audio):
+         add querying of fps lists for webcams.  Negotiating to a framerate
+         now works.
+
 2004-06-08  Thomas Vander Stichele  <thomas at apestaart dot org>
 
        * ext/theora/theoraenc.c: (theora_buffer_from_packet),
index 82ddbc8..66564a0 100644 (file)
 #include <string.h>
 #include <sys/time.h>
 #include "v4lsrc_calls.h"
+#include <sys/ioctl.h>
+
+/* FIXME: small cheat */
+gboolean gst_v4l_set_window_properties (GstV4lElement * v4lelement);
 
 /* elementfactory information */
 static GstElementDetails gst_v4lsrc_details =
@@ -273,6 +277,68 @@ gst_v4lsrc_close (GstElement * element, const gchar * device)
   v4lsrc->colourspaces = NULL;
 }
 
+/* get a list of possible framerates
+ * this is only done for webcams;
+ * other devices return NULL here.
+ */
+static GValue *
+gst_v4lsrc_get_fps_list (GstV4lSrc * v4lsrc)
+{
+  gint fps_index;
+  gfloat fps;
+  struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
+  GstV4lElement *v4lelement = GST_V4LELEMENT (v4lsrc);
+
+  /* check if we have vwin window properties giving a framerate,
+   * as is done for webcams
+   * See http://www.smcc.demon.nl/webcam/api.html
+   * which is used for the Philips and qce-ga drivers */
+  fps_index = (vwin->flags >> 16) & 0x3F;       /* 6 bit index for framerate */
+
+  /* webcams have a non-zero fps_index */
+  if (fps_index == 0) {
+    GST_DEBUG_OBJECT (v4lsrc, "fps_index is 0, no webcam");
+    return NULL;
+  }
+  GST_DEBUG_OBJECT (v4lsrc, "fps_index is %d, so webcam", fps_index);
+
+  {
+    gfloat current_fps;
+    int i;
+    GValue *list = NULL;
+    GValue value = { 0 };
+
+    /* webcam detected, so try all framerates and return a list */
+
+    list = g_new0 (GValue, 1);
+    g_value_init (list, GST_TYPE_LIST);
+
+    /* index of 16 corresponds to 15 fps */
+    current_fps = fps_index * 15.0 / 16;
+    GST_DEBUG_OBJECT (v4lsrc, "device reports fps of %.4f", current_fps);
+    for (i = 1; i < 63; ++i) {
+      /* set bits 16 to 21 to 0 */
+      vwin->flags &= (0x3F00 - 1);
+      /* set bits 16 to 21 to the index */
+      vwin->flags |= i << 16;
+      if (gst_v4l_set_window_properties (v4lelement)) {
+        /* setting it succeeded.  FIXME: get it and check. */
+        fps = i * 15.0 / 16;
+        g_value_init (&value, G_TYPE_DOUBLE);
+        g_value_set_double (&value, fps);
+        gst_value_list_append_value (list, &value);
+        g_value_unset (&value);
+      }
+    }
+    /* FIXME: set back the original fps_index */
+    vwin->flags &= (0x3F00 - 1);
+    vwin->flags |= fps_index << 16;
+    gst_v4l_set_window_properties (v4lelement);
+    return list;
+  }
+  return NULL;
+}
+
 static gfloat
 gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc)
 {
@@ -286,9 +352,16 @@ gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc)
    * See http://www.smcc.demon.nl/webcam/api.html
    * which is used for the Philips and qce-ga drivers */
   fps_index = (vwin->flags >> 16) & 0x3F;       /* 6 bit index for framerate */
-  if (fps_index != 0)
+
+  /* webcams have a non-zero fps_index */
+  if (fps_index != 0) {
+    gfloat current_fps;
+
     /* index of 16 corresponds to 15 fps */
-    return fps_index * 15.0 / 16;
+    current_fps = fps_index * 15.0 / 16;
+    GST_LOG_OBJECT (v4lsrc, "device reports fps of %.3f", current_fps);
+    return current_fps;
+  }
 
   if (!v4lsrc->use_fixed_fps && v4lsrc->clock != NULL && v4lsrc->handled > 0) {
     /* try to get time from clock master and calculate fps */
@@ -508,6 +581,21 @@ gst_v4lsrc_srcconnect (GstPad * pad, const GstCaps * vscapslist)
   gst_structure_get_int (structure, "height", &h);
   gst_structure_get_double (structure, "framerate", &fps);
 
+  /* set framerate if it's not already correct */
+  if (fps != gst_v4lsrc_get_fps (v4lsrc)) {
+    int fps_index = fps / 15.0 * 16;
+    struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
+
+    GST_DEBUG_OBJECT (v4lsrc, "Trying to set fps index %d", fps_index);
+    /* set bits 16 to 21 to 0 */
+    vwin->flags &= (0x3F00 - 1);
+    /* set bits 16 to 21 to the index */
+    vwin->flags |= fps_index << 16;
+    if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) {
+      GST_ELEMENT_ERROR (v4lsrc, RESOURCE, SETTINGS, (NULL),
+          ("Could not set framerate of %d fps", fps));
+    }
+  }
   switch (fourcc) {
     case GST_MAKE_FOURCC ('I', '4', '2', '0'):
       palette = VIDEO_PALETTE_YUV420P;
@@ -626,14 +714,19 @@ gst_v4lsrc_getcaps (GstPad * pad)
   GstCaps *list;
   GstV4lSrc *v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
   struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
-  gfloat fps;
+  gfloat fps = 0.0;
   GList *item;
+  static GValue *fps_list;      /* FIXME: this should be done in a hash table
+                                 * on device name instead */
 
   if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
     return gst_caps_new_any ();
   }
-
-  fps = gst_v4lsrc_get_fps (v4lsrc);
+  /* if not cached from last run, get it */
+  if (!fps_list)
+    fps_list = gst_v4lsrc_get_fps_list (v4lsrc);
+  if (!fps_list)
+    fps = gst_v4lsrc_get_fps (v4lsrc);
 
   list = gst_caps_new_empty ();
   for (item = v4lsrc->colourspaces; item != NULL; item = item->next) {
@@ -649,7 +742,18 @@ gst_v4lsrc_getcaps (GstPad * pad)
 
     gst_caps_set_simple (one, "width", GST_TYPE_INT_RANGE, vcap->minwidth,
         vcap->maxwidth, "height", GST_TYPE_INT_RANGE, vcap->minheight,
-        vcap->maxheight, "framerate", G_TYPE_DOUBLE, fps, NULL);
+        vcap->maxheight, NULL);
+
+    if (fps_list) {
+      GstStructure *structure = gst_caps_get_structure (one, 0);
+
+      gst_structure_set_value (structure, "framerate", fps_list);
+    } else {
+      GstStructure *structure = gst_caps_get_structure (one, 0);
+
+      gst_structure_set (structure, "framerate", G_TYPE_DOUBLE, fps, NULL);
+    }
+    GST_DEBUG_OBJECT (v4lsrc, "caps: %" GST_PTR_FORMAT, one);
     gst_caps_append (list, one);
   }
 
index af12d1b..d8ed316 100644 (file)
 #include "gstv4lmjpegsrc.h"
 #include "gstv4lmjpegsink.h"
 
-
 GST_DEBUG_CATEGORY_EXTERN (v4l_debug);
 
-#define GST_CATEGORY_DEFAULT v4l_debug
+#define GST_CAT_DEFAULT v4l_debug
 
 static const char *picture_name[] = {
   "Hue",
@@ -98,6 +97,43 @@ gst_v4l_get_capabilities (GstV4lElement * v4lelement)
   return TRUE;
 }
 
+/******************************************************
+ * gst_v4l_set_window_properties():
+ *   set the device's capturing parameters (vwin)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_set_window_properties (GstV4lElement * v4lelement)
+{
+  struct video_window vwin;
+
+  GST_DEBUG_OBJECT (v4lelement, "setting window flags 0x%x to device %s",
+      v4lelement->vwin.flags, v4lelement->videodev);
+  GST_V4L_CHECK_OPEN (v4lelement);
+
+  if (ioctl (v4lelement->video_fd, VIDIOCSWIN, &(v4lelement->vwin)) < 0) {
+    GST_DEBUG_OBJECT (v4lelement,
+        "could not ioctl window properties 0x%x to device %s",
+        v4lelement->vwin.flags, v4lelement->videodev);
+    return FALSE;
+  }
+
+  /* get it again to make sure we have it correctly */
+  if (ioctl (v4lelement->video_fd, VIDIOCGWIN, &(vwin)) < 0) {
+    GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL),
+        ("error getting window properties %s of from device %s",
+            g_strerror (errno), v4lelement->videodev));
+    return FALSE;
+  }
+  if (vwin.flags != v4lelement->vwin.flags) {
+    GST_DEBUG_OBJECT (v4lelement, "set 0x%x but got 0x%x back",
+        v4lelement->vwin.flags, vwin.flags);
+    return FALSE;
+  }
+
+  return TRUE;
+}
 
 /******************************************************
  * gst_v4l_open():