libs/gst/base/: Add ::unlock_stop to basesrc and basesink. This allows an opportunity...
authorJan Schmidt <thaytan@mad.scientist.com>
Mon, 19 Mar 2007 15:01:40 +0000 (15:01 +0000)
committerJan Schmidt <thaytan@mad.scientist.com>
Mon, 19 Mar 2007 15:01:40 +0000 (15:01 +0000)
Original commit message from CVS:
* libs/gst/base/gstbasesink.c: (gst_base_sink_set_flushing),
(gst_base_sink_change_state):
* libs/gst/base/gstbasesink.h:
* libs/gst/base/gstbasesrc.c: (gst_base_src_perform_seek),
(gst_base_src_default_event), (gst_base_src_unlock_stop),
(gst_base_src_deactivate):
* libs/gst/base/gstbasesrc.h:
Add ::unlock_stop to basesrc and basesink. This allows an opportunity
for sub-classes to correctly clear any state they set trying to
unlock, such as clearing out unlock commands from a command fd.
* plugins/elements/gstfdsink.c: (gst_fd_sink_class_init),
(gst_fd_sink_render), (gst_fd_sink_unlock),
(gst_fd_sink_unlock_stop):
* plugins/elements/gstfdsrc.c: (gst_fd_src_class_init),
(gst_fd_src_init), (gst_fd_src_unlock), (gst_fd_src_unlock_stop),
(gst_fd_src_create), (gst_fd_src_get_size), (gst_fd_src_do_seek):
Implement unlock_stop in fdsrc and fdsink.
Implement seeking in fdsrc when a seekable fd is passed, as in
gst-launch-0.10 fdsrc ! ... ! xvimagesink < /path/to/file

ChangeLog
libs/gst/base/gstbasesink.c
libs/gst/base/gstbasesink.h
libs/gst/base/gstbasesrc.c
libs/gst/base/gstbasesrc.h
plugins/elements/gstfdsink.c
plugins/elements/gstfdsrc.c

index 15cca40..891631b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2007-03-19  Jan Schmidt  <thaytan@mad.scientist.com>
+
+       * libs/gst/base/gstbasesink.c: (gst_base_sink_set_flushing),
+       (gst_base_sink_change_state):
+       * libs/gst/base/gstbasesink.h:
+       * libs/gst/base/gstbasesrc.c: (gst_base_src_perform_seek),
+       (gst_base_src_default_event), (gst_base_src_unlock_stop),
+       (gst_base_src_deactivate):
+       * libs/gst/base/gstbasesrc.h:
+       Add ::unlock_stop to basesrc and basesink. This allows an opportunity
+       for sub-classes to correctly clear any state they set trying to
+       unlock, such as clearing out unlock commands from a command fd.
+
+       * plugins/elements/gstfdsink.c: (gst_fd_sink_class_init),
+       (gst_fd_sink_render), (gst_fd_sink_unlock),
+       (gst_fd_sink_unlock_stop):
+       * plugins/elements/gstfdsrc.c: (gst_fd_src_class_init),
+       (gst_fd_src_init), (gst_fd_src_unlock), (gst_fd_src_unlock_stop),
+       (gst_fd_src_create), (gst_fd_src_get_size), (gst_fd_src_do_seek):
+
+       Implement unlock_stop in fdsrc and fdsink.
+       Implement seeking in fdsrc when a seekable fd is passed, as in
+       gst-launch-0.10 fdsrc ! ... ! xvimagesink < /path/to/file
+
 2007-03-19  Wim Taymans  <wim@fluendo.com>
 
        Patch by: Evan Nemerson <evan at coeus dash group dot com>
index 3ac30de..b375caf 100644 (file)
@@ -2245,12 +2245,11 @@ static gboolean
 gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad,
     gboolean flushing)
 {
+  GstBaseSinkClass *bclass;
 
-  if (flushing) {
-    GstBaseSinkClass *bclass;
-
-    bclass = GST_BASE_SINK_GET_CLASS (basesink);
+  bclass = GST_BASE_SINK_GET_CLASS (basesink);
 
+  if (flushing) {
     /* unlock any subclasses, we need to do this before grabbing the
      * PREROLL_LOCK since we hold this lock before going into ::render. */
     if (bclass->unlock)
@@ -2260,7 +2259,11 @@ gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad,
   GST_PAD_PREROLL_LOCK (pad);
   basesink->flushing = flushing;
   if (flushing) {
-    /* step 1, unblock clock sync (if any) or any other blocking thing */
+    /* step 1, now that we have the PREROLL lock, clear our unlock request */
+    if (bclass->unlock_stop)
+      bclass->unlock_stop (basesink);
+
+    /* step 2, unblock clock sync (if any) or any other blocking thing */
     basesink->need_preroll = TRUE;
     if (basesink->clock_id) {
       gst_clock_id_unschedule (basesink->clock_id);
@@ -2868,6 +2871,10 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
         bclass->unlock (basesink);
 
       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+      /* now that we have the PREROLL lock, clear our unlock request */
+      if (bclass->unlock_stop)
+        bclass->unlock_stop (basesink);
+
       basesink->need_preroll = TRUE;
       if (basesink->clock_id) {
         gst_clock_id_unschedule (basesink->clock_id);
index 417c5a0..84073ae 100644 (file)
@@ -114,6 +114,8 @@ struct _GstBaseSink {
  * @stop: Stop processing. Subclasses should use this to close resources.
  * @unlock: Unlock any pending access to the resource. Subclasses should
  *     unblock any blocked function ASAP
+ * @unlock_stop: Clear the previous unlock request. Subclasses should clear
+ *     any state they set during unlock(), such as clearing command queues. 
  * @event: Override this to handle events arriving on the sink pad
  * @preroll: Called to present the preroll buffer if desired
  * @render: Called when a buffer should be presented or output, at the
@@ -174,8 +176,13 @@ struct _GstBaseSinkClass {
   /* fixate sink caps during pull-mode negotiation */
   void         (*fixate)       (GstBaseSink *sink, GstCaps *caps);
 
+  /* Clear a previously indicated unlock request not that unlocking is 
+   * complete. Sub-classes should clear any command queue or indicator they
+   * set during unlock */
+  gboolean      (*unlock_stop)       (GstBaseSink *sink);
+
   /*< private >*/
-  gpointer       _gst_reserved[GST_PADDING_LARGE-3];
+  gpointer       _gst_reserved[GST_PADDING_LARGE-4];
 };
 
 GType gst_base_sink_get_type(void);
index 88385a6..f090a14 100644 (file)
@@ -290,6 +290,7 @@ static gboolean gst_base_src_default_do_seek (GstBaseSrc * src,
 static gboolean gst_base_src_default_query (GstBaseSrc * src, GstQuery * query);
 
 static gboolean gst_base_src_unlock (GstBaseSrc * basesrc);
+static gboolean gst_base_src_unlock_stop (GstBaseSrc * basesrc);
 static gboolean gst_base_src_start (GstBaseSrc * basesrc);
 static gboolean gst_base_src_stop (GstBaseSrc * basesrc);
 
@@ -910,6 +911,9 @@ gst_base_src_perform_seek (GstBaseSrc * src, GstEvent * event, gboolean unlock)
    * because our peer is flushing. */
   GST_PAD_STREAM_LOCK (src->srcpad);
 
+  if (unlock)
+    gst_base_src_unlock_stop (src);
+
   /* make copy into temp structure, we can only update the main one
    * when the subclass actually could do the seek. */
   memcpy (&seeksegment, &src->segment, sizeof (GstSegment));
@@ -1110,6 +1114,8 @@ gst_base_src_default_event (GstBaseSrc * src, GstEvent * event)
       result = gst_base_src_unlock (src);
       break;
     case GST_EVENT_FLUSH_STOP:
+      result = gst_base_src_unlock_stop (src);
+      break;
     default:
       result = TRUE;
       break;
@@ -1687,6 +1693,28 @@ gst_base_src_unlock (GstBaseSrc * basesrc)
   return result;
 }
 
+/* this will always be called between start() and stop(). So you can rely on
+ * resources allocated by start() and freed from stop(). This needs to be added
+ * to the docs at some point. */
+static gboolean
+gst_base_src_unlock_stop (GstBaseSrc * basesrc)
+{
+  GstBaseSrcClass *bclass;
+  gboolean result = TRUE;
+
+  GST_DEBUG_OBJECT (basesrc, "unlock stop");
+
+  /* Finish a previous unblock request, allowing subclasses to flush command
+   * queues or whatever they need to do */
+  bclass = GST_BASE_SRC_GET_CLASS (basesrc);
+  if (bclass->unlock_stop)
+    result = bclass->unlock_stop (basesrc);
+
+  GST_DEBUG_OBJECT (basesrc, "unlock stop done");
+
+  return result;
+}
+
 /* default negotiation code. 
  *
  * Take intersection between src and sink pads, take first
@@ -1906,6 +1934,9 @@ gst_base_src_deactivate (GstBaseSrc * basesrc, GstPad * pad)
   /* step 2, make sure streaming finishes */
   result &= gst_pad_stop_task (pad);
 
+  /* step 3, clear the unblock condition */
+  result &= gst_base_src_unlock_stop (basesrc);
+
   return result;
 }
 
index fc9ed50..0acf741 100644 (file)
@@ -132,6 +132,8 @@ struct _GstBaseSrc {
  * @is_seekable: Check if the source can seek
  * @unlock: Unlock any pending access to the resource. Subclasses should
  *    unblock any blocked function ASAP
+ * @unlock_stop: Clear the previous unlock request. Subclasses should clear
+ *    any state they set during unlock(), such as clearing command queues. 
  * @event: Override this to implement custom event handling.
  * @create: Ask the subclass to create a buffer with offset and size.
  * @do_seek: Perform seeking on the resource to the indicated segment.
@@ -208,8 +210,11 @@ struct _GstBaseSrcClass {
   /* called if, in negotation, caps need fixating */
   void         (*fixate)       (GstBaseSrc *src, GstCaps *caps);
 
+  /* Clear any pending unlock request, as we succeeded in unlocking */
+  gboolean      (*unlock_stop)  (GstBaseSrc *src);
+
   /*< private >*/
-  gpointer       _gst_reserved[GST_PADDING_LARGE - 4];
+  gpointer       _gst_reserved[GST_PADDING_LARGE - 5];
 };
 
 GType gst_base_src_get_type (void);
index e9f398e..9c3789e 100644 (file)
@@ -141,6 +141,7 @@ static GstFlowReturn gst_fd_sink_render (GstBaseSink * sink,
 static gboolean gst_fd_sink_start (GstBaseSink * basesink);
 static gboolean gst_fd_sink_stop (GstBaseSink * basesink);
 static gboolean gst_fd_sink_unlock (GstBaseSink * basesink);
+static gboolean gst_fd_sink_unlock_stop (GstBaseSink * basesink);
 
 static void
 gst_fd_sink_base_init (gpointer g_class)
@@ -170,6 +171,7 @@ gst_fd_sink_class_init (GstFdSinkClass * klass)
   gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_fd_sink_start);
   gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_fd_sink_stop);
   gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock);
+  gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_sink_unlock_stop);
   gstbasesink_class->event = NULL;
 
   g_object_class_install_property (gobject_class, ARG_FD,
@@ -272,21 +274,8 @@ again:
   if (retval == -1)
     goto select_error;
 
-  if (FD_ISSET (READ_SOCKET (fdsink), &readfds)) {
-    /* read all stop commands */
-    while (TRUE) {
-      gchar command;
-      int res;
-
-      READ_COMMAND (fdsink, command, res);
-      if (res < 0) {
-        GST_LOG_OBJECT (fdsink, "no more commands");
-        /* no more commands */
-        break;
-      }
-    }
+  if (FD_ISSET (READ_SOCKET (fdsink), &readfds))
     goto stopped;
-  }
 #endif
 
   GST_DEBUG_OBJECT (fdsink, "writing %d bytes to file descriptor %d", size,
@@ -437,12 +426,36 @@ gst_fd_sink_unlock (GstBaseSink * basesink)
 {
   GstFdSink *fdsink = GST_FD_SINK (basesink);
 
+  GST_LOG_OBJECT (fdsink, "Sending unlock command to queue");
   SEND_COMMAND (fdsink, CONTROL_STOP);
 
   return TRUE;
 }
 
 static gboolean
+gst_fd_sink_unlock_stop (GstBaseSink * basesink)
+{
+  GstFdSink *fdsink = GST_FD_SINK (basesink);
+
+  /* read all stop commands */
+  GST_LOG_OBJECT (fdsink, "Clearing unlock command queue");
+
+  while (TRUE) {
+    gchar command;
+    int res;
+
+    READ_COMMAND (fdsink, command, res);
+    if (res < 0) {
+      GST_LOG_OBJECT (fdsink, "no more commands");
+      /* no more commands */
+      break;
+    }
+  }
+
+  return TRUE;
+}
+
+static gboolean
 gst_fd_sink_update_fd (GstFdSink * fdsink, int new_fd)
 {
   if (new_fd < 0)
index 3961555..c8941ca 100644 (file)
@@ -119,8 +119,10 @@ static void gst_fd_src_dispose (GObject * obj);
 static gboolean gst_fd_src_start (GstBaseSrc * bsrc);
 static gboolean gst_fd_src_stop (GstBaseSrc * bsrc);
 static gboolean gst_fd_src_unlock (GstBaseSrc * bsrc);
+static gboolean gst_fd_src_unlock_stop (GstBaseSrc * bsrc);
 static gboolean gst_fd_src_is_seekable (GstBaseSrc * bsrc);
 static gboolean gst_fd_src_get_size (GstBaseSrc * src, guint64 * size);
+static gboolean gst_fd_src_do_seek (GstBaseSrc * src, GstSegment * segment);
 
 static GstFlowReturn gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf);
 
@@ -160,8 +162,10 @@ gst_fd_src_class_init (GstFdSrcClass * klass)
   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_fd_src_start);
   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_fd_src_stop);
   gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_fd_src_unlock);
+  gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_fd_src_unlock_stop);
   gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fd_src_is_seekable);
   gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_fd_src_get_size);
+  gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_fd_src_do_seek);
 
   gstpush_src_class->create = GST_DEBUG_FUNCPTR (gst_fd_src_create);
 }
@@ -169,10 +173,10 @@ gst_fd_src_class_init (GstFdSrcClass * klass)
 static void
 gst_fd_src_init (GstFdSrc * fdsrc, GstFdSrcClass * klass)
 {
-  fdsrc->fd = 0;
+  fdsrc->fd = -1;
   fdsrc->new_fd = 0;
   fdsrc->seekable_fd = FALSE;
-  fdsrc->uri = g_strdup_printf ("fd://%d", fdsrc->fd);
+  fdsrc->uri = g_strdup_printf ("fd://0");
   fdsrc->curoffset = 0;
 }
 
@@ -268,11 +272,37 @@ gst_fd_src_unlock (GstBaseSrc * bsrc)
 {
   GstFdSrc *src = GST_FD_SRC (bsrc);
 
+  GST_LOG_OBJECT (src, "sending unlock command");
   SEND_COMMAND (src, CONTROL_STOP);
 
   return TRUE;
 }
 
+static gboolean
+gst_fd_src_unlock_stop (GstBaseSrc * bsrc)
+{
+  GstFdSrc *src = GST_FD_SRC (bsrc);
+
+  GST_LOG_OBJECT (src, "clearing unlock command queue");
+
+  /* read all stop commands */
+  while (TRUE) {
+    gchar command;
+    int res;
+
+    GST_LOG_OBJECT (src, "reading command");
+
+    READ_COMMAND (src, command, res);
+    if (res < 0) {
+      GST_LOG_OBJECT (src, "no more commands");
+      /* no more commands */
+      break;
+    }
+  }
+
+  return TRUE;
+}
+
 static void
 gst_fd_src_set_property (GObject * object, guint prop_id, const GValue * value,
     GParamSpec * pspec)
@@ -343,23 +373,8 @@ gst_fd_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
   if (retval == -1)
     goto select_error;
 
-  if (FD_ISSET (READ_SOCKET (src), &readfds)) {
-    /* read all stop commands */
-    while (TRUE) {
-      gchar command;
-      int res;
-
-      GST_LOG_OBJECT (src, "reading command");
-
-      READ_COMMAND (src, command, res);
-      if (res < 0) {
-        GST_LOG_OBJECT (src, "no more commands");
-        /* no more commands */
-        break;
-      }
-    }
+  if (FD_ISSET (READ_SOCKET (src), &readfds))
     goto stopped;
-  }
 #endif
 
   blocksize = GST_BASE_SRC (src)->blocksize;
@@ -453,7 +468,33 @@ could_not_stat:
   {
     return FALSE;
   }
+}
+
+gboolean
+gst_fd_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
+{
+  gint res;
+  gint64 offset;
+  GstFdSrc *src = GST_FD_SRC (bsrc);
+
+  offset = segment->start;
+
+  /* No need to seek to the current position */
+  if (offset == src->curoffset)
+    return TRUE;
+
+  res = lseek (src->fd, offset, SEEK_SET);
+  if (G_UNLIKELY (res < 0 || res != offset))
+    goto seek_failed;
+
+  segment->last_stop = segment->start;
+  segment->time = segment->start;
+
+  return TRUE;
 
+seek_failed:
+  GST_DEBUG_OBJECT (src, "lseek returned %" G_GINT64_FORMAT, offset);
+  return FALSE;
 }
 
 /*** GSTURIHANDLER INTERFACE *************************************************/