stepping: more stepping improvements
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 12 Jun 2009 11:18:21 +0000 (13:18 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 12 Jun 2009 11:20:36 +0000 (13:20 +0200)
Update design doc with step-start docs.
Add eos field to step done message
when stepping in reverse, update the segment time field.
Flush out the current step when we are flushing.

docs/design/draft-framestep.txt
gst/gstmessage.c
gst/gstmessage.h
gst/gstquark.c
gst/gstquark.h
libs/gst/base/gstbasesink.c
tests/examples/stepping/framestep1.c

index cdc064b..f76518e 100644 (file)
@@ -170,6 +170,39 @@ events
 messages
 --------
 
+ A GST_MESSAGE_STEP_START is created. It contains the following fields.
+
+  "active"
+     If the step was queued or activated.
+
+  "format", GST_TYPE_FORMAT
+     The format of the step units that queued/activated.
+
+  "amount", G_TYPE_UINT64
+     The amount of units that were queued/activated.
+
+  "rate", G_TYPE_DOUBLE
+     The rate and direction at which the frames were queued/activated.
+
+  "flush", G_TYPE_BOOLEAN
+     If the queued/activated frames will be flushed.
+
+  "intermediate", G_TYPE_BOOLEAN
+     If this is an intermediate step operation that queued/activated.
+
+ The STEP_START message is emited 2 times:
+  * first when an element received the STEP event and queued it. The "active"
+    field will be FALSE in this case.
+
+  * second when the step operation started in the streaming thread. The "active"
+    field is TRUE in this case. After this message is emited, the application
+    can queue a new step operation.
+
+ The purpose of this message is to find out how many elements participate in the
+ step operation and to queue new step operations at the earliest possible
+ moment.
+
  A new GST_MESSAGE_STEP_DONE message is created. It contains the following
  fields:
 
@@ -191,6 +224,9 @@ messages
   "duration", G_TYPE_UINT64
      The total duration of the stepped units in GST_FORMAT_TIME.
 
+  "eos", G_TYPE_BOOLEAN
+     The step ended because of EOS.
+
  The message is emited by the element that performs the step operation. The
  purpose is to return the duration in GST_FORMAT_TIME of the stepped media. This
  especially interesting to align other stream in case of stepping frames on the
index c8f042b..fa4606a 100644 (file)
@@ -1645,6 +1645,7 @@ gst_message_get_stream_status_object (GstMessage * message)
  * @flush: is this an flushing step
  * @intermediate: is this an intermediate step
  * @duration: the duration of the data
+ * @eos: the step caused EOS
  *
  * This message is posted by elements when they complete a part, when @intermediate set
  * to TRUE, or a complete step operation.
@@ -1660,7 +1661,8 @@ gst_message_get_stream_status_object (GstMessage * message)
  */
 GstMessage *
 gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
-    gdouble rate, gboolean flush, gboolean intermediate, guint64 duration)
+    gdouble rate, gboolean flush, gboolean intermediate, guint64 duration,
+    gboolean eos)
 {
   GstMessage *message;
   GstStructure *structure;
@@ -1671,7 +1673,8 @@ gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
       GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
       GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
       GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate,
-      GST_QUARK (DURATION), G_TYPE_UINT64, duration, NULL);
+      GST_QUARK (DURATION), G_TYPE_UINT64, duration,
+      GST_QUARK (EOS), G_TYPE_BOOLEAN, eos, NULL);
   message = gst_message_new_custom (GST_MESSAGE_STEP_DONE, src, structure);
 
   return message;
@@ -1686,6 +1689,7 @@ gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
  * @flush: result location for the flush flag
  * @intermediate: result location for the intermediate flag
  * @duration: result location for the duration
+ * @eos: result location for the EOS flag
  *
  * Extract the requested state from the request_state message.
  *
@@ -1696,56 +1700,52 @@ gst_message_new_step_done (GstObject * src, GstFormat format, guint64 amount,
 void
 gst_message_parse_step_done (GstMessage * message, GstFormat * format,
     guint64 * amount, gdouble * rate, gboolean * flush, gboolean * intermediate,
-    guint64 * duration)
+    guint64 * duration, gboolean * eos)
 {
   g_return_if_fail (GST_IS_MESSAGE (message));
   g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STEP_DONE);
 
-  if (format)
-    *format = g_value_get_enum (gst_structure_id_get_value (message->structure,
-            GST_QUARK (FORMAT)));
-  if (amount)
-    *amount =
-        g_value_get_uint64 (gst_structure_id_get_value (message->structure,
-            GST_QUARK (AMOUNT)));
-  if (rate)
-    *rate = g_value_get_double (gst_structure_id_get_value (message->structure,
-            GST_QUARK (RATE)));
-  if (flush)
-    *flush =
-        g_value_get_boolean (gst_structure_id_get_value (message->structure,
-            GST_QUARK (FLUSH)));
-  if (intermediate)
-    *intermediate =
-        g_value_get_boolean (gst_structure_id_get_value (message->structure,
-            GST_QUARK (INTERMEDIATE)));
-  if (duration)
-    *duration =
-        g_value_get_uint64 (gst_structure_id_get_value (message->structure,
-            GST_QUARK (DURATION)));
+  gst_structure_id_get (message->structure,
+      GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
+      GST_QUARK (AMOUNT), G_TYPE_UINT64, amount,
+      GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
+      GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
+      GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate,
+      GST_QUARK (EOS), G_TYPE_BOOLEAN, eos, NULL);
 }
 
 GstMessage *
-gst_message_new_step_start (GstObject * src, gboolean active)
+gst_message_new_step_start (GstObject * src, gboolean active, GstFormat format,
+    guint64 amount, gdouble rate, gboolean flush, gboolean intermediate)
 {
   GstMessage *message;
   GstStructure *structure;
 
   structure = gst_structure_id_new (GST_QUARK (MESSAGE_STEP_START),
-      GST_QUARK (ACTIVE), G_TYPE_BOOLEAN, active, NULL);
+      GST_QUARK (ACTIVE), G_TYPE_BOOLEAN, active,
+      GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
+      GST_QUARK (AMOUNT), G_TYPE_UINT64, amount,
+      GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
+      GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
+      GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, NULL);
   message = gst_message_new_custom (GST_MESSAGE_STEP_START, src, structure);
 
   return message;
 }
 
 void
-gst_message_parse_step_start (GstMessage * message, gboolean * active)
+gst_message_parse_step_start (GstMessage * message, gboolean * active,
+    GstFormat * format, guint64 * amount, gdouble * rate, gboolean * flush,
+    gboolean * intermediate)
 {
   g_return_if_fail (GST_IS_MESSAGE (message));
   g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STEP_START);
 
-  if (active)
-    *active =
-        g_value_get_boolean (gst_structure_id_get_value (message->structure,
-            GST_QUARK (ACTIVE)));
+  gst_structure_id_get (message->structure,
+      GST_QUARK (ACTIVE), G_TYPE_BOOLEAN, active,
+      GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
+      GST_QUARK (AMOUNT), G_TYPE_UINT64, amount,
+      GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
+      GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
+      GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, NULL);
 }
index 9103669..fa06e3a 100644 (file)
@@ -399,10 +399,10 @@ GstMessage *      gst_message_new_state_dirty     (GstObject * src);
 /* STEP_DONE */
 GstMessage *    gst_message_new_step_done       (GstObject * src, GstFormat format, guint64 amount,
                                                  gdouble rate, gboolean flush, gboolean intermediate, 
-                                                guint64 duration);
+                                                guint64 duration, gboolean eos);
 void            gst_message_parse_step_done     (GstMessage * message, GstFormat *format, guint64 *amount,
                                                  gdouble *rate, gboolean *flush, gboolean *intermediate,
-                                                guint64 *duration);
+                                                guint64 *duration, gboolean *eos);
 /* CLOCK_PROVIDE */
 GstMessage *   gst_message_new_clock_provide   (GstObject * src, GstClock *clock, gboolean ready);
 void           gst_message_parse_clock_provide (GstMessage *message, GstClock **clock,
@@ -466,8 +466,12 @@ GstMessage *    gst_message_new_request_state   (GstObject * src, GstState state
 void            gst_message_parse_request_state (GstMessage * message, GstState *state);
 
 /* STEP_START */
-GstMessage *    gst_message_new_step_start      (GstObject * src, gboolean active);
-void            gst_message_parse_step_start    (GstMessage * message, gboolean *active);
+GstMessage *    gst_message_new_step_start      (GstObject * src, gboolean active, GstFormat format,
+                                                 guint64 amount, gdouble rate, gboolean flush,
+                                                gboolean intermediate);
+void            gst_message_parse_step_start    (GstMessage * message, gboolean *active, GstFormat *format,
+                                                 guint64 *amount, gdouble *rate, gboolean *flush,
+                                                gboolean *intermediate);
 
 /* custom messages */
 GstMessage *   gst_message_new_custom          (GstMessageType type,
index 6a898b3..957f43c 100644 (file)
@@ -47,7 +47,7 @@ static const gchar *_quark_strings[] = {
   "GstQueryPosition", "GstQueryDuration", "GstQueryLatency", "GstQueryConvert",
   "GstQuerySegment", "GstQuerySeeking", "GstQueryFormats", "GstQueryBuffering",
   "GstQueryURI", "GstEventStep", "GstMessageStepDone", "amount", "flush",
-  "intermediate", "GstMessageStepStart", "active"
+  "intermediate", "GstMessageStepStart", "active", "eos"
 };
 
 GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index ec48893..234883e 100644 (file)
@@ -116,8 +116,9 @@ typedef enum _GstQuarkId
   GST_QUARK_INTERMEDIATE = 87,
   GST_QUARK_MESSAGE_STEP_START = 88,
   GST_QUARK_ACTIVE = 89,
+  GST_QUARK_EOS = 90,
 
-  GST_QUARK_MAX = 90
+  GST_QUARK_MAX = 91
 } GstQuarkId;
 
 extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index 91197eb..a0b9d48 100644 (file)
@@ -1495,7 +1495,9 @@ start_stepping (GstBaseSink * sink, GstSegment * segment,
   GST_OBJECT_UNLOCK (sink);
 
   /* post message first */
-  message = gst_message_new_step_start (GST_OBJECT (sink), TRUE);
+  message =
+      gst_message_new_step_start (GST_OBJECT (sink), TRUE, current->format,
+      current->amount, current->rate, current->flush, current->intermediate);
   gst_message_set_seqnum (message, current->seqnum);
   gst_element_post_message (GST_ELEMENT (sink), message);
 
@@ -1518,16 +1520,28 @@ start_stepping (GstBaseSink * sink, GstSegment * segment,
     end = current->start + current->amount;
     if (!current->flush) {
       /* update the segment clipping regions for non-flushing seeks */
-      if (segment->rate > 0.0)
+      if (segment->rate > 0.0) {
         segment->stop = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
-      else
-        segment->start =
-            gst_segment_to_position (segment, GST_FORMAT_TIME, end);
+        segment->last_stop = segment->stop;
+      } else {
+        gint64 position;
+
+        position = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
+        segment->time = position;
+        segment->start = position;
+        segment->last_stop = position;
+      }
     }
   }
 
-  GST_DEBUG_OBJECT (sink, "segment now %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
-      GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop));
+  GST_DEBUG_OBJECT (sink,
+      "segment now rate %lf, applied rate %lf, "
+      "format GST_FORMAT_TIME, "
+      "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
+      ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
+      segment->rate, segment->applied_rate, GST_TIME_ARGS (segment->start),
+      GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
+      GST_TIME_ARGS (segment->accum));
 
   GST_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT,
       GST_TIME_ARGS (current->start));
@@ -1544,7 +1558,7 @@ start_stepping (GstBaseSink * sink, GstSegment * segment,
 
 static void
 stop_stepping (GstBaseSink * sink, GstSegment * segment,
-    GstStepInfo * current, gint64 rstart, gint64 rstop)
+    GstStepInfo * current, gint64 rstart, gint64 rstop, gboolean eos)
 {
   gint64 stop, position;
   GstMessage *message;
@@ -1596,7 +1610,7 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment,
   message =
       gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format,
       current->amount, current->rate, current->flush, current->intermediate,
-      current->duration);
+      current->duration, eos);
   gst_message_set_seqnum (message, current->seqnum);
   gst_element_post_message (GST_ELEMENT_CAST (sink), message);
 
@@ -1711,6 +1725,7 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
   GstClockTime sstart, sstop;   /* clipped timestamps converted to stream time */
   GstFormat format;
   GstBaseSinkPrivate *priv;
+  gboolean eos;
 
   priv = basesink->priv;
 
@@ -1746,6 +1761,7 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
             GST_TIME_ARGS (rstart));
         /* if we are stepping, we end now */
         *step_end = step->valid;
+        eos = TRUE;
         goto eos_done;
       }
       default:
@@ -1759,6 +1775,8 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
     }
   }
 
+  eos = FALSE;
+
   /* else do buffer sync code */
   buffer = GST_BUFFER_CAST (obj);
 
@@ -1799,6 +1817,7 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
   if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME,
               (gint64) start, (gint64) stop, &cstart, &cstop))) {
     if (step->valid) {
+      GST_DEBUG_OBJECT (basesink, "step out of segment");
       /* when we are stepping, pretend we're at the end of the segment */
       if (segment->rate > 0.0) {
         cstart = segment->stop;
@@ -1841,10 +1860,10 @@ do_times:
   sstop = gst_segment_to_stream_time (segment, format, cstop);
 
 eos_done:
-  /* done label only called when doing EOS, we also stop stepping then */
+  /* eos_done label only called when doing EOS, we also stop stepping then */
   if (*step_end && step->flush) {
     GST_DEBUG_OBJECT (basesink, "flushing step ended");
-    stop_stepping (basesink, segment, step, rstart, rstop);
+    stop_stepping (basesink, segment, step, rstart, rstop, eos);
     *step_end = FALSE;
   }
 
@@ -2326,6 +2345,7 @@ flushing:
 preroll_failed:
   {
     GST_DEBUG_OBJECT (basesink, "preroll failed");
+    *step_end = FALSE;
     return ret;
   }
 }
@@ -2674,6 +2694,9 @@ again:
       if (ret == GST_FLOW_STEP)
         goto again;
 
+      if (G_UNLIKELY (basesink->flushing))
+        goto flushing;
+
       priv->rendered++;
     }
   } else {
@@ -2739,7 +2762,7 @@ done:
     /* the step ended, check if we need to activate a new step */
     GST_DEBUG_OBJECT (basesink, "step ended");
     stop_stepping (basesink, &basesink->segment, &priv->current_step,
-        priv->current_rstart, priv->current_rstop);
+        priv->current_rstart, priv->current_rstop, basesink->eos);
     goto again;
   }
 
@@ -3550,8 +3573,9 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
   current = &priv->current_step;
 
   /* post message first */
-  message = gst_message_new_step_start (GST_OBJECT (sink), FALSE);
-  gst_message_set_seqnum (message, current->seqnum);
+  message = gst_message_new_step_start (GST_OBJECT (sink), FALSE, format,
+      amount, rate, flush, intermediate);
+  gst_message_set_seqnum (message, seqnum);
   gst_element_post_message (GST_ELEMENT (sink), message);
 
   if (flush) {
index ddf82a2..e188284 100644 (file)
@@ -39,9 +39,10 @@ event_loop (GstElement * pipe)
         gdouble rate;
         gboolean flush, intermediate;
         guint64 duration;
+        gboolean eos;
 
         gst_message_parse_step_done (message, &format, &amount, &rate,
-            &flush, &intermediate, &duration);
+            &flush, &intermediate, &duration, &eos);
 
         if (format == GST_FORMAT_DEFAULT) {
           g_message ("step done: %" GST_TIME_FORMAT " skipped in %"