This patch fixes some issues caused by design issues in video4linux, adds some nicety...
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>
Fri, 20 Sep 2002 09:28:46 +0000 (09:28 +0000)
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>
Fri, 20 Sep 2002 09:28:46 +0000 (09:28 +0000)
Original commit message from CVS:
This patch fixes some issues caused by design issues in video4linux, adds
some nicety to video4linux2 plugins and does some more evil stuff:
* video4linux doesn't tell us which formats are supported by a card, so
the only way to know this is by simply trying it out. This patch adds that.
* v4lmjpegsink didnt have a bufferpool yet - is integrated now.
* all copy() bufferpool functions have been removed since they're not needed.
* v4lmjpegsink doesnt have a free() function, because hen playing the frames,
all this is already handled. When the frame is not played, nothing has to
be done. In total, the function is not needed.
* adds a get_caps() function to v4l2src
* some minor crap

sys/v4l/TODO
sys/v4l/gstv4lmjpegsink.c
sys/v4l/gstv4lmjpegsink.h
sys/v4l/gstv4lmjpegsrc.c
sys/v4l/gstv4lsrc.c
sys/v4l/v4lsrc_calls.c
sys/v4l/v4lsrc_calls.h

index 7e91b3b..4afe5fb 100644 (file)
@@ -1,24 +1,14 @@
 TODO list (short term):
 =======================
-* as soon as we've trashed Gtk-1.2, change 'gint palette'
-    to 'guint16 palette' in gstv4lsrc.[ch]
-* v4lsrc: actually try the format out on capsnego
-* all plugins: on try_set_caps(), loop try_set_caps() per caps
-    instead of using a multi-caps so we know the end-format
-* all three: fix interlacing (not handled at all...)
-* add overlay handling in v4lelement
-* libgstrec
-* avidemux: add events (seek)
-* avimux: fps calculations (or make that a set/get_property()?)
+* v4lsrc/v4lmjpegsrc/v4l2src: fix interlacing (not handled at all...)
 
 TODO list (long term):
 ======================
 * v4lmpegsrc (*hint* MPEG card needed *hint*)
-* v4l2element && v4l2src
+* v4l2sink
 * BSD-videosrc (meteorsrc?)
 * color correction (brightness, hue, etc.)
 * gamma correction
-* dxr3sink
 
 Useful Documentation:
 =====================
index 092cb5a..93bfd5a 100644 (file)
@@ -71,6 +71,12 @@ static void                  gst_v4lmjpegsink_get_property (GObject
 static GstElementStateReturn gst_v4lmjpegsink_change_state (GstElement           *element);
 static void                 gst_v4lmjpegsink_set_clock    (GstElement *element, GstClock *clock);
 
+/* bufferpool functions */
+static GstBuffer*            gst_v4lmjpegsink_buffer_new   (GstBufferPool  *pool,
+                                                            guint64        offset,
+                                                            guint          size,
+                                                            gpointer       user_data);
+
 
 static GstCaps *capslist = NULL;
 static GstPadTemplate *sink_template;
@@ -174,6 +180,14 @@ gst_v4lmjpegsink_init (GstV4lMjpegSink *v4lmjpegsink)
   v4lmjpegsink->bufsize = 256;
 
   GST_FLAG_SET(v4lmjpegsink, GST_ELEMENT_THREAD_SUGGESTED);
+
+  v4lmjpegsink->bufferpool = gst_buffer_pool_new(
+                                 NULL, 
+                                 NULL,
+                                 gst_v4lmjpegsink_buffer_new,
+                                 NULL,
+                                 NULL,
+                                 v4lmjpegsink);
 }
 
 
@@ -259,20 +273,28 @@ gst_v4lmjpegsink_chain (GstPad    *pad,
     gst_element_clock_wait(GST_ELEMENT(v4lmjpegsink), v4lmjpegsink->clock, GST_BUFFER_TIMESTAMP(buf), NULL);
   }
 
-  /* check size */
-  if (GST_BUFFER_SIZE(buf) > v4lmjpegsink->breq.size)
+  if (GST_BUFFER_POOL(buf) == v4lmjpegsink->bufferpool)
   {
-    gst_element_error(GST_ELEMENT(v4lmjpegsink),
-      "Buffer too big (%d KB), max. buffersize is %d KB",
-      GST_BUFFER_SIZE(buf)/1024, v4lmjpegsink->breq.size/1024);
-    return;
+    num = GPOINTER_TO_INT(GST_BUFFER_POOL_PRIVATE(buf));
+    gst_v4lmjpegsink_play_frame(v4lmjpegsink, num);
+  }
+  else
+  {
+    /* check size */
+    if (GST_BUFFER_SIZE(buf) > v4lmjpegsink->breq.size)
+    {
+      gst_element_error(GST_ELEMENT(v4lmjpegsink),
+        "Buffer too big (%d KB), max. buffersize is %d KB",
+        GST_BUFFER_SIZE(buf)/1024, v4lmjpegsink->breq.size/1024);
+      return;
+    }
+
+    /* put JPEG data to the device */
+    gst_v4lmjpegsink_wait_frame(v4lmjpegsink, &num);
+    memcpy(gst_v4lmjpegsink_get_buffer(v4lmjpegsink, num),
+      GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
+    gst_v4lmjpegsink_play_frame(v4lmjpegsink, num);
   }
-
-  /* put JPEG data to the device */
-  gst_v4lmjpegsink_wait_frame(v4lmjpegsink, &num);
-  memcpy(gst_v4lmjpegsink_get_buffer(v4lmjpegsink, num),
-    GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
-  gst_v4lmjpegsink_play_frame(v4lmjpegsink, num);
 
   g_signal_emit(G_OBJECT(v4lmjpegsink),gst_v4lmjpegsink_signals[SIGNAL_FRAME_DISPLAYED],0);
 
@@ -280,6 +302,43 @@ gst_v4lmjpegsink_chain (GstPad    *pad,
 }
 
 
+static GstBuffer *
+gst_v4lmjpegsink_buffer_new (GstBufferPool *pool,
+                             guint64        offset,
+                             guint          size,
+                             gpointer       user_data)
+{
+  GstV4lMjpegSink *v4lmjpegsink = GST_V4LMJPEGSINK(user_data);
+  GstBuffer *buffer = NULL;
+  guint8 *data;
+  gint num;
+
+  if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsink)))
+    return NULL;
+  if (v4lmjpegsink->breq.size < size) {
+    GST_DEBUG(GST_CAT_PLUGIN_INFO, "Requested buffer size is too large (%d > %ld)",
+      size, v4lmjpegsink->breq.size);
+    return NULL;
+  }
+  if (!gst_v4lmjpegsink_wait_frame(v4lmjpegsink, &num))
+    return NULL;
+  data = gst_v4lmjpegsink_get_buffer(v4lmjpegsink, num);
+  if (!data)
+    return NULL;
+  buffer = gst_buffer_new();
+  GST_BUFFER_DATA(buffer) = data;
+  GST_BUFFER_MAXSIZE(buffer) = v4lmjpegsink->breq.size;
+  GST_BUFFER_SIZE(buffer) = size;
+  GST_BUFFER_POOL(buffer) = pool;
+  GST_BUFFER_POOL_PRIVATE(buffer) = GINT_TO_POINTER(num);
+
+  /* with this flag set, we don't need our own buffer_free() function */
+  GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
+
+  return buffer;
+}
+
+
 static void
 gst_v4lmjpegsink_set_property (GObject      *object,
                                guint        prop_id,
index a981049..1eee8d9 100644 (file)
@@ -68,6 +68,9 @@ struct _GstV4lMjpegSink {
   pthread_cond_t *cond_queued_frames;
   gint current_frame;
 
+  /* something to get our buffers from */
+  GstBufferPool *bufferpool;
+
   /* width/height/norm of the jpeg stream */
   gint width;
   gint height;
index 0b0e676..5ca9534 100644 (file)
@@ -86,9 +86,6 @@ static GstBuffer*            gst_v4lmjpegsrc_buffer_new   (GstBufferPool  *pool,
                                                            guint64        location,
                                                            guint          size,
                                                            gpointer       user_data);
-static GstBuffer*            gst_v4lmjpegsrc_buffer_copy  (GstBufferPool  *pool,
-                                                          const GstBuffer *srcbuf,
-                                                           gpointer       user_data);
 static void                  gst_v4lmjpegsrc_buffer_free  (GstBufferPool  *pool,
                                                           GstBuffer      *buf,
                                                            gpointer       user_data);
@@ -195,7 +192,7 @@ gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc)
                                        NULL,
                                        NULL,
                                        gst_v4lmjpegsrc_buffer_new,
-                                       gst_v4lmjpegsrc_buffer_copy,
+                                       NULL,
                                        gst_v4lmjpegsrc_buffer_free,
                                        v4lmjpegsrc);
 
@@ -553,28 +550,18 @@ gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
                             gpointer      user_data)
 {
   GstBuffer *buffer;
+  GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC(user_data);
+
+  if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
+    return NULL;
 
   buffer = gst_buffer_new();
-  if (!buffer) return NULL;
+  if (!buffer)
+    return NULL;
 
   /* TODO: add interlacing info to buffer as metadata */
-
-  return buffer;
-}
-
-
-static GstBuffer*
-gst_v4lmjpegsrc_buffer_copy (GstBufferPool *pool, const GstBuffer *srcbuf, gpointer user_data)
-{
-  GstBuffer *buffer;
-
-  buffer = gst_buffer_new();
-  if (!buffer) return NULL;
-  GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(srcbuf));
-  if (!GST_BUFFER_DATA(buffer)) return NULL;
-  GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
-  memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(srcbuf), GST_BUFFER_SIZE(srcbuf));
-  GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP(srcbuf);
+  GST_BUFFER_MAXSIZE(buffer) = v4lmjpegsrc->breq.size;
+  GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
 
   return buffer;
 }
@@ -586,15 +573,22 @@ gst_v4lmjpegsrc_buffer_free (GstBufferPool *pool, GstBuffer *buf, gpointer user_
   GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (user_data);
   int n;
 
+  if (gst_element_get_state(GST_ELEMENT(v4lmjpegsrc)) != GST_STATE_PLAYING)
+    return; /* we've already cleaned up ourselves */
+
   for (n=0;n<v4lmjpegsrc->breq.count;n++)
     if (GST_BUFFER_DATA(buf) == gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, n))
     {
       gst_v4lmjpegsrc_requeue_frame(v4lmjpegsrc, n);
-      return;
+      break;
     }
 
-  gst_element_error(GST_ELEMENT(v4lmjpegsrc),
-    "Couldn't find the buffer");
+  if (n == v4lmjpegsrc->breq.count)
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Couldn't find the buffer");
+
+  /* free the buffer struct et all */
+  gst_buffer_default_free(buf);
 }
 
 
index a51d687..d3d9c0d 100644 (file)
@@ -82,9 +82,6 @@ static GstBuffer*            gst_v4lsrc_buffer_new   (GstBufferPool  *pool,
                                                       guint64        offset,
                                                       guint          size,
                                                       gpointer       user_data);
-static GstBuffer*            gst_v4lsrc_buffer_copy  (GstBufferPool  *pool,
-                                                     const GstBuffer *srcbuf,
-                                                     gpointer       user_data);
 static void                  gst_v4lsrc_buffer_free  (GstBufferPool  *pool,
                                                      GstBuffer      *buf,
                                                      gpointer       user_data);
@@ -172,7 +169,7 @@ gst_v4lsrc_init (GstV4lSrc *v4lsrc)
                  NULL, 
                  NULL,
                  gst_v4lsrc_buffer_new,
-                 gst_v4lsrc_buffer_copy,
+                 NULL,
                  gst_v4lsrc_buffer_free,
                  v4lsrc);
 
@@ -388,9 +385,8 @@ gst_v4lsrc_srcconnect (GstPad  *pad,
 
   /* 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))
+    /* try the current 'palette' out on the video device */
+    if (!gst_v4lsrc_try_palette(v4lsrc, palette))
       continue;
 
     /* try to connect the pad/caps with the actual width/height */
@@ -428,6 +424,9 @@ gst_v4lsrc_srcconnect (GstPad  *pad,
     else if (ret_val == GST_PAD_CONNECT_DELAYED)
       return GST_PAD_CONNECT_DELAYED;
 
+    if (!gst_v4lsrc_set_capture(v4lsrc, v4lsrc->width, v4lsrc->height, palette))
+      return GST_PAD_CONNECT_REFUSED;
+
     if (!gst_v4lsrc_capture_init(v4lsrc))
       return GST_PAD_CONNECT_REFUSED;
 
@@ -616,27 +615,19 @@ gst_v4lsrc_buffer_new (GstBufferPool *pool,
                        gpointer      user_data)
 {
   GstBuffer *buffer;
+  GstV4lSrc *v4lsrc = GST_V4LSRC(user_data);
 
-  buffer = gst_buffer_new();
-  if (!buffer) return NULL;
-  /* TODO: add interlacing info to buffer as metadata (height>288 or 240 = topfieldfirst, else noninterlaced) */
-
-  return buffer;
-}
-
-
-static GstBuffer*
-gst_v4lsrc_buffer_copy (GstBufferPool *pool, const GstBuffer *srcbuf, gpointer user_data)
-{
-  GstBuffer *buffer;
+  if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc)))
+    return NULL;
 
   buffer = gst_buffer_new();
-  if (!buffer) return NULL;
-  GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(srcbuf));
-  if (!GST_BUFFER_DATA(buffer)) return NULL;
-  GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
-  memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(srcbuf), GST_BUFFER_SIZE(srcbuf));
-  GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP(srcbuf);
+  if (!buffer)
+    return NULL;
+
+  /* TODO: add interlacing info to buffer as metadata
+   * (height>288 or 240 = topfieldfirst, else noninterlaced) */
+  GST_BUFFER_MAXSIZE(buffer) = v4lsrc->mbuf.size / v4lsrc->mbuf.frames;
+  GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
 
   return buffer;
 }
@@ -648,15 +639,22 @@ gst_v4lsrc_buffer_free (GstBufferPool *pool, GstBuffer *buf, gpointer user_data)
   GstV4lSrc *v4lsrc = GST_V4LSRC (user_data);
   int n;
 
+  if (gst_element_get_state(GST_ELEMENT(v4lsrc)) != GST_STATE_PLAYING)
+    return; /* we've already cleaned up ourselves */
+
   for (n=0;n<v4lsrc->mbuf.frames;n++)
     if (GST_BUFFER_DATA(buf) == gst_v4lsrc_get_buffer(v4lsrc, n))
     {
       gst_v4lsrc_requeue_frame(v4lsrc, n);
-      return;
+      break;
     }
 
-  gst_element_error(GST_ELEMENT(v4lsrc),
-    "Couldn\'t find the buffer");
+  if (n == v4lsrc->mbuf.frames)
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Couldn\'t find the buffer");
+
+  /* free struct */
+  gst_buffer_default_free(buf);
 }
 
 
index 960fc77..40cd6cf 100644 (file)
@@ -493,3 +493,85 @@ gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc)
 
   return TRUE;
 }
+
+
+/******************************************************
+ * gst_v4lsrc_try_palette():
+ *   try out a palette on the device
+ *   This has to be done before initializing the
+ *   actual capture system, to make sure we don't
+ *   mess up anything. So we need to mini-mmap()
+ *   a buffer here, queue and sync on one buffer,
+ *   and unmap it.
+ *   This is ugly, yes, I know - but it's a major
+ *   design flaw of v4l1 that you don't know in
+ *   advance which formats will be supported...
+ *   This is better than "just assuming that it'll
+ *   work"...
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lsrc_try_palette (GstV4lSrc *v4lsrc,
+                        gint       palette)
+{
+  /* so, we need a buffer and some more stuff */
+  int frame = 0;
+  guint8 *buffer;
+  struct video_mbuf vmbuf;
+  struct video_mmap vmmap;
+
+  DEBUG("gonna try out palette format %d (%s)",
+    palette, palette_name[palette]);
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
+  GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lsrc));
+
+  /* let's start by requesting a buffer and mmap()'ing it */
+  if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCGMBUF, &vmbuf) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Error getting buffer information: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+  /* Map the buffers */
+  buffer = mmap(0, vmbuf.size, PROT_READ|PROT_WRITE,
+                MAP_SHARED, GST_V4LELEMENT(v4lsrc)->video_fd, 0);
+  if (buffer == MAP_FAILED)
+  {
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Error mapping our try-out buffer: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  /* now that we have a buffer, let's try out our format */
+  vmmap.width = GST_V4LELEMENT(v4lsrc)->vcap.minwidth;
+  vmmap.height = GST_V4LELEMENT(v4lsrc)->vcap.minheight;
+  vmmap.format = palette;
+  vmmap.frame = frame;
+  if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCMCAPTURE, &vmmap) < 0)
+  {
+    if (errno != EINVAL) /* our format failed! */
+      gst_element_error(GST_ELEMENT(v4lsrc),
+        "Error queueing our try-out buffer: %s",
+        sys_errlist[errno]);
+    munmap(buffer, vmbuf.size);
+    return FALSE;
+  }
+
+  if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCSYNC, &frame) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Error syncing on a buffer (%d): %s",
+      frame, sys_errlist[errno]);
+    munmap(buffer, vmbuf.size);
+    return FALSE;
+  }
+
+  munmap(buffer, vmbuf.size);
+
+  /* if we got here, it worked! woohoo, the format is supported! */
+  return TRUE;
+}
+
index a85735c..0af1f81 100644 (file)
@@ -41,6 +41,9 @@ gboolean gst_v4lsrc_requeue_frame  (GstV4lSrc *v4lsrc, gint  num);
 gboolean gst_v4lsrc_capture_stop   (GstV4lSrc *v4lsrc);
 gboolean gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc);
 
+/* "the ugliest hack ever, now available at your local mirror" */
+gboolean gst_v4lsrc_try_palette    (GstV4lSrc *v4lsrc, gint palette);
+
 
 #ifdef __cplusplus
 }