]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gstreamer0-10.git/commitdiff
gst/base/gstbasesink.*: Store and use discont values when syncing buffers as describe...
authorWim Taymans <wim.taymans@gmail.com>
Sat, 16 Jul 2005 14:41:25 +0000 (14:41 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Sat, 16 Jul 2005 14:41:25 +0000 (14:41 +0000)
Original commit message from CVS:
* gst/base/gstbasesink.c: (gst_base_sink_handle_object),
(gst_base_sink_event), (gst_base_sink_get_times),
(gst_base_sink_do_sync), (gst_base_sink_change_state):
* gst/base/gstbasesink.h:
Store and use discont values when syncing buffers as described
in design docs.

* gst/base/gstbasesrc.c: (gst_base_src_send_discont),
(gst_base_src_do_seek), (gst_base_src_loop), (gst_base_src_start),
(gst_base_src_activate_push):
Push discont event when starting.

* gst/elements/gstidentity.c: (gst_identity_transform):
Small cleanups.

* gst/gstbin.c: (gst_bin_change_state):
Small cleanups in base_time  distribution.

* gst/gstelement.c: (gst_element_set_base_time),
(gst_element_get_base_time), (gst_element_change_state):
* gst/gstelement.h:
Added methods for the base_time of the element.
Some MT fixes.

* gst/gstpipeline.c: (gst_pipeline_send_event),
(gst_pipeline_change_state), (gst_pipeline_set_new_stream_time),
(gst_pipeline_get_last_stream_time):
* gst/gstpipeline.h:
MT fixes.
Handle seeking as described in design doc, remove stream_time
hack.
Cleanups clock and stream_time selection code. Added accessors
for the stream_time.

14 files changed:
ChangeLog
gst/base/gstbasesink.c
gst/base/gstbasesink.h
gst/base/gstbasesrc.c
gst/elements/gstidentity.c
gst/gstbin.c
gst/gstelement.c
gst/gstelement.h
gst/gstpipeline.c
gst/gstpipeline.h
libs/gst/base/gstbasesink.c
libs/gst/base/gstbasesink.h
libs/gst/base/gstbasesrc.c
plugins/elements/gstidentity.c

index 054ef8c6d3aa27e4e01b53400557dc0d35b40ea6..4a40454b8fe2ca8a3ed47e870626d8a2045ee8d1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2005-07-16  Wim Taymans  <wim@fluendo.com>
+
+       * gst/base/gstbasesink.c: (gst_base_sink_handle_object),
+       (gst_base_sink_event), (gst_base_sink_get_times),
+       (gst_base_sink_do_sync), (gst_base_sink_change_state):
+       * gst/base/gstbasesink.h:
+       Store and use discont values when syncing buffers as described
+       in design docs.
+       
+       * gst/base/gstbasesrc.c: (gst_base_src_send_discont),
+       (gst_base_src_do_seek), (gst_base_src_loop), (gst_base_src_start),
+       (gst_base_src_activate_push):
+       Push discont event when starting.
+
+       * gst/elements/gstidentity.c: (gst_identity_transform):
+       Small cleanups.
+
+       * gst/gstbin.c: (gst_bin_change_state):
+       Small cleanups in base_time  distribution.
+
+       * gst/gstelement.c: (gst_element_set_base_time),
+       (gst_element_get_base_time), (gst_element_change_state):
+       * gst/gstelement.h:
+       Added methods for the base_time of the element.
+       Some MT fixes.
+
+       * gst/gstpipeline.c: (gst_pipeline_send_event),
+       (gst_pipeline_change_state), (gst_pipeline_set_new_stream_time),
+       (gst_pipeline_get_last_stream_time):
+       * gst/gstpipeline.h:
+       MT fixes.
+       Handle seeking as described in design doc, remove stream_time
+       hack.
+       Cleanups clock and stream_time selection code. Added accessors
+       for the stream_time.
+       
+
 2005-07-16  Andy Wingo  <wingo@pobox.com>
 
        * gst/gsterror.c (_gst_core_errors_init): Use the magic word..
index ae7d15731c87b8188007532cb051edc932814d3f..47945ca324a298782d3b2c57d2991e2cc219effe 100644 (file)
@@ -455,16 +455,37 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
 
   have_event = GST_IS_EVENT (obj);
   if (have_event) {
+    GstEvent *event = GST_EVENT (obj);
+
     switch (GST_EVENT_TYPE (obj)) {
       case GST_EVENT_EOS:
         basesink->preroll_queued++;
         basesink->eos = TRUE;
         break;
+      case GST_EVENT_DISCONTINUOUS:
+        /* the discont event is needed to bring the buffer timestamps to the
+         * stream time */
+        if (!gst_event_discont_get_value (event, GST_FORMAT_TIME,
+                &basesink->discont_start, &basesink->discont_stop)) {
+          basesink->discont_start = 0;
+          basesink->discont_stop = 0;
+        }
+        basesink->have_discont = TRUE;
+
+        GST_DEBUG ("received DISCONT %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
+            GST_TIME_ARGS (basesink->discont_start),
+            GST_TIME_ARGS (basesink->discont_stop));
+        break;
       default:
         break;
     }
     basesink->events_queued++;
   } else {
+    if (!basesink->have_discont) {
+      GST_ELEMENT_ERROR (basesink, STREAM, STOPPED,
+          ("received buffer without a discont"),
+          ("received buffer without a discont"));
+    }
     basesink->preroll_queued++;
     basesink->buffers_queued++;
   }
@@ -641,9 +662,6 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
       GstFlowReturn ret;
 
       GST_STREAM_LOCK (pad);
-      if (basesink->clock) {
-        //gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
-      }
       ret =
           gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
       GST_STREAM_UNLOCK (pad);
@@ -693,7 +711,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
 }
 
 /* default implementation to calculate the start and end
- * timestamps on a buffer, subclasses cna override
+ * timestamps on a buffer, subclasses can override
  */
 static void
 gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
@@ -703,6 +721,10 @@ gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
 
   timestamp = GST_BUFFER_TIMESTAMP (buffer);
   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    /* bring timestamp to stream time using last
+     * discont offset. */
+    timestamp -= basesink->discont_start;
+    /* get duration to calculate end time */
     duration = GST_BUFFER_DURATION (buffer);
     if (GST_CLOCK_TIME_IS_VALID (duration)) {
       *end = timestamp + duration;
@@ -739,11 +761,17 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
 
     if (GST_CLOCK_TIME_IS_VALID (start)) {
       GstClockReturn ret;
+      GstClockTime base_time;
 
-      /* save clock id so that we can unlock it if needed */
       GST_LOCK (basesink);
+      base_time = GST_ELEMENT (basesink)->base_time;
+
+      GST_LOG_OBJECT (basesink,
+          "waiting for clock, base time %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (base_time));
+      /* save clock id so that we can unlock it if needed */
       basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
-          start + GST_ELEMENT (basesink)->base_time);
+          start + base_time);
       basesink->end_time = end;
       GST_UNLOCK (basesink);
 
@@ -995,6 +1023,9 @@ gst_base_sink_change_state (GstElement * element)
       basesink->have_preroll = FALSE;
       basesink->need_preroll = TRUE;
       GST_PREROLL_UNLOCK (basesink->sinkpad);
+      basesink->have_discont = FALSE;
+      basesink->discont_start = 0;
+      basesink->discont_stop = 0;
       ret = GST_STATE_ASYNC;
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
index 312d7c4b883fd8ca575fc4f3b1d586a7c8ae1b60..c7fc83e4d6a791ffbaf9885dbae8d0d8c0fc7662 100644 (file)
@@ -66,6 +66,10 @@ struct _GstBaseSink {
   GstClockID     clock_id;
   GstClockTime   end_time;
 
+  gboolean      have_discont;
+  GstClockTime  discont_start;
+  GstClockTime  discont_stop;
+
   gboolean       eos;
   gboolean       need_preroll;
   gboolean       have_preroll;
index 88720a0a5ee1b43bd6cf3e97181443c2f6e00697..f866bf0a32e37ebfc69d43596bd9b621f33d4536 100644 (file)
@@ -356,6 +356,18 @@ gst_base_src_get_event_mask (GstPad * pad)
 }
 #endif
 
+static gboolean
+gst_base_src_send_discont (GstBaseSrc * src)
+{
+  GstEvent *event;
+
+  event = gst_event_new_discontinuous (1.0,
+      GST_FORMAT_BYTES,
+      (gint64) src->segment_start, (gint64) src->segment_end, NULL);
+
+  return gst_pad_push_event (src->srcpad, event);
+}
+
 static gboolean
 gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
 {
@@ -420,15 +432,7 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
   gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
 
   /* now send discont */
-  {
-    GstEvent *event;
-
-    event = gst_event_new_discontinuous (1.0,
-        GST_FORMAT_BYTES,
-        (gint64) src->segment_start, (gint64) src->segment_end, NULL);
-
-    gst_pad_push_event (src->srcpad, event);
-  }
+  gst_base_src_send_discont (src);
 
   /* and restart the task */
   gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,
@@ -864,7 +868,7 @@ gst_base_src_start (GstBaseSrc * basesrc)
   GST_DEBUG ("size %d %lld", result, basesrc->size);
 
   /* we always run to the end */
-  basesrc->segment_end = -1;
+  basesrc->segment_end = basesrc->size;
 
   /* check if we can seek, updates ->seekable */
   gst_base_src_is_seekable (basesrc);
@@ -952,6 +956,9 @@ gst_base_src_activate_push (GstPad * pad, gboolean active)
     if (!gst_base_src_start (basesrc))
       goto error_start;
 
+    /* now send discont */
+    gst_base_src_send_discont (basesrc);
+
     return gst_pad_start_task (pad, (GstTaskFunction) gst_base_src_loop, pad);
   } else {
     return gst_base_src_deactivate (basesrc, pad);
index f73015dbe840e1a192380d151dd83ca05963d53b..090f6514e28bff5c437e7a2f59f641afea9280da 100644 (file)
@@ -360,27 +360,28 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
 
   if (identity->sync) {
     GstClock *clock;
-    GstClockReturn cret;
 
-    clock = GST_ELEMENT (identity)->clock;
+    GST_LOCK (identity);
+    if ((clock = GST_ELEMENT (identity)->clock)) {
+      GstClockReturn cret;
 
-    if (clock) {
       /* save id if we need to unlock */
-      /* FIXME: actually unlock this somewhere if the state changes */
-      GST_LOCK (identity);
+      /* FIXME: actually unlock this somewhere in the state changes */
       identity->clock_id = gst_clock_new_single_shot_id (clock,
           GST_BUFFER_TIMESTAMP (outbuf) + GST_ELEMENT (identity)->base_time);
       GST_UNLOCK (identity);
+
       cret = gst_clock_id_wait (identity->clock_id, NULL);
+
       GST_LOCK (identity);
       if (identity->clock_id) {
         gst_clock_id_unref (identity->clock_id);
         identity->clock_id = NULL;
       }
-      GST_UNLOCK (identity);
       if (cret == GST_CLOCK_UNSCHEDULED)
         ret = GST_FLOW_UNEXPECTED;
     }
+    GST_UNLOCK (identity);
   }
 
   identity->offset += GST_BUFFER_SIZE (outbuf);
index e2b6bd3c4542467f52d98664bec72596d7eba863..5a38c6402ff90da1e3804ca8de75d526f21e1dbf 100644 (file)
@@ -1135,6 +1135,7 @@ gst_bin_change_state (GstElement * element)
   GQueue *elem_queue;           /* list of elements waiting for a state change */
   GQueue *semi_queue;           /* list of elements with no connected srcpads */
   GQueue *temp;                 /* queue of leftovers */
+  GstClockTime base_time;
 
   bin = GST_BIN (element);
 
@@ -1167,6 +1168,9 @@ gst_bin_change_state (GstElement * element)
   GST_LOCK (bin);
 
 restart:
+  /* take base time */
+  base_time = element->base_time;
+
   /* make sure queues are empty, they could be filled when 
    * restarting. */
   clear_queue (elem_queue, TRUE);
@@ -1286,7 +1290,9 @@ restart:
       goto next_element;
 
     /* set base time on element */
-    qelement->base_time = element->base_time;
+    gst_element_set_base_time (qelement, base_time);
+
+    /* then change state */
     ret = gst_element_set_state (qelement, pending);
 
     /* the set state could have cause elements to be added/removed,
index 544da34d458076916d8e558949e532ec7b7714e3..3d5698d3c76eaa34af6c3f284480d58937998fc3 100644 (file)
@@ -362,6 +362,52 @@ gst_element_get_clock (GstElement * element)
   return NULL;
 }
 
+/**
+ * gst_element_set_base_time:
+ * @element: a #GstElement.
+ * @time: the base time to set.
+ *
+ * Set the base time of an element. See @gst_element_get_base_time().
+ *
+ * MT safe.
+ */
+void
+gst_element_set_base_time (GstElement * element, GstClockTime time)
+{
+  g_return_if_fail (GST_IS_ELEMENT (element));
+
+  GST_LOCK (element);
+  element->base_time = time;
+  GST_UNLOCK (element);
+}
+
+/**
+ * gst_element_get_base_time:
+ * @element: a #GstElement.
+ *
+ * Returns the base time of the element. The base time is the
+ * absolute time of the clock when this element was last put to
+ * PLAYING. Substracting the base time from the clock time gives
+ * the stream time of the element.
+ *
+ * Returns: the base time of the element.
+ *
+ * MT safe.
+ */
+GstClockTime
+gst_element_get_base_time (GstElement * element)
+{
+  GstClockTime result;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE);
+
+  GST_LOCK (element);
+  result = element->base_time;
+  GST_UNLOCK (element);
+
+  return result;
+}
+
 #ifndef GST_DISABLE_INDEX
 /**
  * gst_element_is_indexable:
@@ -1953,6 +1999,7 @@ gst_element_change_state (GstElement * element)
       }
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
+      /* FIXME really needed? */
       GST_LOCK (element);
       if (GST_ELEMENT_MANAGER (element)) {
         element->base_time =
@@ -1969,7 +2016,9 @@ gst_element_change_state (GstElement * element)
       if (!gst_element_pads_activate (element, FALSE)) {
         result = GST_STATE_FAILURE;
       } else {
+        GST_LOCK (element);
         element->base_time = 0;
+        GST_UNLOCK (element);
       }
       break;
     default:
index d9b3d9fd2552a6df6f5692f5eab90112461c17fa..98c6385bb45018226c7f838cda2bc167f58148ff 100644 (file)
@@ -281,6 +281,8 @@ gboolean            gst_element_requires_clock      (GstElement *element);
 gboolean               gst_element_provides_clock      (GstElement *element);
 GstClock*              gst_element_get_clock           (GstElement *element);
 void                   gst_element_set_clock           (GstElement *element, GstClock *clock);
+void                   gst_element_set_base_time       (GstElement *element, GstClockTime time);
+GstClockTime           gst_element_get_base_time       (GstElement *element);
 
 /* indexes */
 gboolean               gst_element_is_indexable        (GstElement *element);
index 6c0ad24ef3c5c7e7344dfa579f58c08cb3f2dfb5..421aa9def089ffafa3b76fe33ed5679197871cae 100644 (file)
@@ -229,7 +229,6 @@ gst_pipeline_send_event (GstElement * element, GstEvent * event)
   GstElementState state;
   GstEventType event_type = GST_EVENT_TYPE (event);
   GTimeVal timeout;
-  gint64 offset = -1;
 
   /* need to call _get_state() since a bin state is only updated
    * with this call. */
@@ -239,12 +238,6 @@ gst_pipeline_send_event (GstElement * element, GstEvent * event)
   was_playing = state == GST_STATE_PLAYING;
 
   if (event_type == GST_EVENT_SEEK) {
-    if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_TIME) {
-      GST_WARNING ("Pipelines only accept seek events with TIME format");
-      g_warning ("Pipelines only accept seek events with TIME format");
-      return FALSE;
-    }
-    offset = GST_EVENT_SEEK_OFFSET (event);
     if (was_playing)
       gst_element_set_state (element, GST_STATE_PAUSED);
   }
@@ -253,7 +246,7 @@ gst_pipeline_send_event (GstElement * element, GstEvent * event)
 
   if (res && event_type == GST_EVENT_SEEK) {
     /* need to set the stream time to the seek time */
-    GST_PIPELINE (element)->stream_time = offset;
+    gst_pipeline_set_new_stream_time (GST_PIPELINE (element), 0);
     if (was_playing)
       gst_element_set_state (element, GST_STATE_PLAYING);
   }
@@ -284,35 +277,42 @@ gst_pipeline_change_state (GstElement * element)
   GstElementStateReturn result = GST_STATE_SUCCESS;
   GstPipeline *pipeline = GST_PIPELINE (element);
   gint transition = GST_STATE_TRANSITION (element);
+  GstClock *clock;
 
   switch (transition) {
     case GST_STATE_NULL_TO_READY:
+      GST_LOCK (element);
       if (element->bus)
         gst_bus_set_flushing (element->bus, FALSE);
+      GST_UNLOCK (element);
       gst_scheduler_setup (GST_ELEMENT_SCHEDULER (pipeline));
       break;
     case GST_STATE_READY_TO_PAUSED:
-    {
-      GstClock *clock;
-
-      clock = gst_element_get_clock (element);
-      gst_element_set_clock (element, clock);
-      gst_object_unref (clock);
       break;
-    }
     case GST_STATE_PAUSED_TO_PLAYING:
-      if (element->clock) {
-        GstClockTime start_time = gst_clock_get_time (element->clock);
+      /* when going to playing, select a clock */
+      if ((clock = gst_element_get_clock (element))) {
+        GstClockTime start_time;
+
+        /* distribute the clock */
+        gst_element_set_clock (element, clock);
+
+        /* get start time */
+        start_time = gst_clock_get_time (clock);
+        gst_object_unref (clock);
 
+        GST_LOCK (element);
         element->base_time = start_time -
             pipeline->stream_time + pipeline->delay;
         GST_DEBUG ("stream_time=%" GST_TIME_FORMAT ", start_time=%"
             GST_TIME_FORMAT ", base time %" GST_TIME_FORMAT,
             GST_TIME_ARGS (pipeline->stream_time),
             GST_TIME_ARGS (start_time), GST_TIME_ARGS (element->base_time));
+        GST_UNLOCK (element);
       } else {
-        element->base_time = 0;
+        GST_UNLOCK (element);
         GST_DEBUG ("no clock, using base time of 0");
+        gst_element_set_base_time (element, 0);
       }
       break;
     case GST_STATE_PLAYING_TO_PAUSED:
@@ -325,28 +325,40 @@ gst_pipeline_change_state (GstElement * element)
 
   switch (transition) {
     case GST_STATE_READY_TO_PAUSED:
-      pipeline->stream_time = 0;
+      gst_pipeline_set_new_stream_time (pipeline, 0);
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
       break;
     case GST_STATE_PLAYING_TO_PAUSED:
-      if (element->clock) {
+      GST_LOCK (element);
+      if ((clock = element->clock)) {
         GstClockTime now;
 
-        now = gst_clock_get_time (element->clock);
+        gst_object_ref (clock);
+        GST_UNLOCK (element);
+
+        /* calculate the time when we stopped */
+        now = gst_clock_get_time (clock);
+        gst_object_unref (clock);
+
+        GST_LOCK (element);
+        /* store the current stream time */
         pipeline->stream_time = now - element->base_time;
         GST_DEBUG ("stream_time=%" GST_TIME_FORMAT ", now=%" GST_TIME_FORMAT
             ", base time %" GST_TIME_FORMAT,
             GST_TIME_ARGS (pipeline->stream_time),
             GST_TIME_ARGS (now), GST_TIME_ARGS (element->base_time));
       }
+      GST_UNLOCK (element);
       break;
     case GST_STATE_PAUSED_TO_READY:
       break;
     case GST_STATE_READY_TO_NULL:
+      GST_LOCK (element);
       if (element->bus) {
         gst_bus_set_flushing (element->bus, TRUE);
       }
+      GST_UNLOCK (element);
       break;
   }
 
@@ -412,6 +424,55 @@ gst_pipeline_get_bus (GstPipeline * pipeline)
   return gst_element_get_bus (GST_ELEMENT (pipeline));
 }
 
+/**
+ * gst_pipeline_set_new_stream_time:
+ * @pipeline: the pipeline
+ *
+ * Set the new stream time of the pipeline. The stream time is used to
+ * set the base time on the elements (see @gst_element_set_base_time())
+ * in the PAUSED->PLAYING state transition.
+ *
+ * MT safe.
+ */
+void
+gst_pipeline_set_new_stream_time (GstPipeline * pipeline, GstClockTime time)
+{
+  g_return_if_fail (GST_IS_PIPELINE (pipeline));
+
+  GST_LOCK (pipeline);
+  pipeline->stream_time = time;
+  GST_DEBUG ("%s: set new stream_time to %" GST_TIME_FORMAT,
+      GST_ELEMENT_NAME (pipeline), time);
+  GST_UNLOCK (pipeline);
+}
+
+/**
+ * gst_pipeline_get_last_stream_time:
+ * @pipeline: the pipeline
+ *
+ * Gets the last stream time of the pipeline. If the pipeline is PLAYING,
+ * the returned time is the stream time used to configure the elements
+ * in the PAUSED->PLAYING state. If the pipeline is PAUSED, the returned
+ * time is the stream time when the pipeline was paused.
+ *
+ * Returns: a GstClockTime
+ *
+ * MT safe.
+ */
+GstClockTime
+gst_pipeline_get_last_stream_time (GstPipeline * pipeline)
+{
+  GstClockTime result;
+
+  g_return_val_if_fail (GST_IS_PIPELINE (pipeline), GST_CLOCK_TIME_NONE);
+
+  GST_LOCK (pipeline);
+  result = pipeline->stream_time;
+  GST_UNLOCK (pipeline);
+
+  return result;
+}
+
 static GstClock *
 gst_pipeline_get_clock_func (GstElement * element)
 {
index 2f3cdae4276d1b7de1e3e3ed5488d7bcda28af6a..014106161386b840c300cf106ab26edae3e88d76 100644 (file)
@@ -70,6 +70,9 @@ GstElement*   gst_pipeline_new                (const gchar *name);
 GstScheduler*  gst_pipeline_get_scheduler      (GstPipeline *pipeline);
 GstBus*                gst_pipeline_get_bus            (GstPipeline *pipeline);
 
+void           gst_pipeline_set_new_stream_time  (GstPipeline *pipeline, GstClockTime time);
+GstClockTime   gst_pipeline_get_last_stream_time (GstPipeline *pipeline);
+
 void            gst_pipeline_use_clock          (GstPipeline *pipeline, GstClock *clock);
 void            gst_pipeline_set_clock          (GstPipeline *pipeline, GstClock *clock);
 GstClock*       gst_pipeline_get_clock          (GstPipeline *pipeline);
index ae7d15731c87b8188007532cb051edc932814d3f..47945ca324a298782d3b2c57d2991e2cc219effe 100644 (file)
@@ -455,16 +455,37 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
 
   have_event = GST_IS_EVENT (obj);
   if (have_event) {
+    GstEvent *event = GST_EVENT (obj);
+
     switch (GST_EVENT_TYPE (obj)) {
       case GST_EVENT_EOS:
         basesink->preroll_queued++;
         basesink->eos = TRUE;
         break;
+      case GST_EVENT_DISCONTINUOUS:
+        /* the discont event is needed to bring the buffer timestamps to the
+         * stream time */
+        if (!gst_event_discont_get_value (event, GST_FORMAT_TIME,
+                &basesink->discont_start, &basesink->discont_stop)) {
+          basesink->discont_start = 0;
+          basesink->discont_stop = 0;
+        }
+        basesink->have_discont = TRUE;
+
+        GST_DEBUG ("received DISCONT %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
+            GST_TIME_ARGS (basesink->discont_start),
+            GST_TIME_ARGS (basesink->discont_stop));
+        break;
       default:
         break;
     }
     basesink->events_queued++;
   } else {
+    if (!basesink->have_discont) {
+      GST_ELEMENT_ERROR (basesink, STREAM, STOPPED,
+          ("received buffer without a discont"),
+          ("received buffer without a discont"));
+    }
     basesink->preroll_queued++;
     basesink->buffers_queued++;
   }
@@ -641,9 +662,6 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
       GstFlowReturn ret;
 
       GST_STREAM_LOCK (pad);
-      if (basesink->clock) {
-        //gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
-      }
       ret =
           gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
       GST_STREAM_UNLOCK (pad);
@@ -693,7 +711,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
 }
 
 /* default implementation to calculate the start and end
- * timestamps on a buffer, subclasses cna override
+ * timestamps on a buffer, subclasses can override
  */
 static void
 gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
@@ -703,6 +721,10 @@ gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
 
   timestamp = GST_BUFFER_TIMESTAMP (buffer);
   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    /* bring timestamp to stream time using last
+     * discont offset. */
+    timestamp -= basesink->discont_start;
+    /* get duration to calculate end time */
     duration = GST_BUFFER_DURATION (buffer);
     if (GST_CLOCK_TIME_IS_VALID (duration)) {
       *end = timestamp + duration;
@@ -739,11 +761,17 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
 
     if (GST_CLOCK_TIME_IS_VALID (start)) {
       GstClockReturn ret;
+      GstClockTime base_time;
 
-      /* save clock id so that we can unlock it if needed */
       GST_LOCK (basesink);
+      base_time = GST_ELEMENT (basesink)->base_time;
+
+      GST_LOG_OBJECT (basesink,
+          "waiting for clock, base time %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (base_time));
+      /* save clock id so that we can unlock it if needed */
       basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
-          start + GST_ELEMENT (basesink)->base_time);
+          start + base_time);
       basesink->end_time = end;
       GST_UNLOCK (basesink);
 
@@ -995,6 +1023,9 @@ gst_base_sink_change_state (GstElement * element)
       basesink->have_preroll = FALSE;
       basesink->need_preroll = TRUE;
       GST_PREROLL_UNLOCK (basesink->sinkpad);
+      basesink->have_discont = FALSE;
+      basesink->discont_start = 0;
+      basesink->discont_stop = 0;
       ret = GST_STATE_ASYNC;
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
index 312d7c4b883fd8ca575fc4f3b1d586a7c8ae1b60..c7fc83e4d6a791ffbaf9885dbae8d0d8c0fc7662 100644 (file)
@@ -66,6 +66,10 @@ struct _GstBaseSink {
   GstClockID     clock_id;
   GstClockTime   end_time;
 
+  gboolean      have_discont;
+  GstClockTime  discont_start;
+  GstClockTime  discont_stop;
+
   gboolean       eos;
   gboolean       need_preroll;
   gboolean       have_preroll;
index 88720a0a5ee1b43bd6cf3e97181443c2f6e00697..f866bf0a32e37ebfc69d43596bd9b621f33d4536 100644 (file)
@@ -356,6 +356,18 @@ gst_base_src_get_event_mask (GstPad * pad)
 }
 #endif
 
+static gboolean
+gst_base_src_send_discont (GstBaseSrc * src)
+{
+  GstEvent *event;
+
+  event = gst_event_new_discontinuous (1.0,
+      GST_FORMAT_BYTES,
+      (gint64) src->segment_start, (gint64) src->segment_end, NULL);
+
+  return gst_pad_push_event (src->srcpad, event);
+}
+
 static gboolean
 gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
 {
@@ -420,15 +432,7 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
   gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
 
   /* now send discont */
-  {
-    GstEvent *event;
-
-    event = gst_event_new_discontinuous (1.0,
-        GST_FORMAT_BYTES,
-        (gint64) src->segment_start, (gint64) src->segment_end, NULL);
-
-    gst_pad_push_event (src->srcpad, event);
-  }
+  gst_base_src_send_discont (src);
 
   /* and restart the task */
   gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,
@@ -864,7 +868,7 @@ gst_base_src_start (GstBaseSrc * basesrc)
   GST_DEBUG ("size %d %lld", result, basesrc->size);
 
   /* we always run to the end */
-  basesrc->segment_end = -1;
+  basesrc->segment_end = basesrc->size;
 
   /* check if we can seek, updates ->seekable */
   gst_base_src_is_seekable (basesrc);
@@ -952,6 +956,9 @@ gst_base_src_activate_push (GstPad * pad, gboolean active)
     if (!gst_base_src_start (basesrc))
       goto error_start;
 
+    /* now send discont */
+    gst_base_src_send_discont (basesrc);
+
     return gst_pad_start_task (pad, (GstTaskFunction) gst_base_src_loop, pad);
   } else {
     return gst_base_src_deactivate (basesrc, pad);
index f73015dbe840e1a192380d151dd83ca05963d53b..090f6514e28bff5c437e7a2f59f641afea9280da 100644 (file)
@@ -360,27 +360,28 @@ gst_identity_transform (GstBaseTransform * trans, GstBuffer * inbuf,
 
   if (identity->sync) {
     GstClock *clock;
-    GstClockReturn cret;
 
-    clock = GST_ELEMENT (identity)->clock;
+    GST_LOCK (identity);
+    if ((clock = GST_ELEMENT (identity)->clock)) {
+      GstClockReturn cret;
 
-    if (clock) {
       /* save id if we need to unlock */
-      /* FIXME: actually unlock this somewhere if the state changes */
-      GST_LOCK (identity);
+      /* FIXME: actually unlock this somewhere in the state changes */
       identity->clock_id = gst_clock_new_single_shot_id (clock,
           GST_BUFFER_TIMESTAMP (outbuf) + GST_ELEMENT (identity)->base_time);
       GST_UNLOCK (identity);
+
       cret = gst_clock_id_wait (identity->clock_id, NULL);
+
       GST_LOCK (identity);
       if (identity->clock_id) {
         gst_clock_id_unref (identity->clock_id);
         identity->clock_id = NULL;
       }
-      GST_UNLOCK (identity);
       if (cret == GST_CLOCK_UNSCHEDULED)
         ret = GST_FLOW_UNEXPECTED;
     }
+    GST_UNLOCK (identity);
   }
 
   identity->offset += GST_BUFFER_SIZE (outbuf);