ext/theora/theoradec.c: Implement reverse playback.
authorWim Taymans <wim.taymans@gmail.com>
Sun, 26 Nov 2006 16:39:41 +0000 (16:39 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Sun, 26 Nov 2006 16:39:41 +0000 (16:39 +0000)
Original commit message from CVS:
* ext/theora/theoradec.c: (gst_theora_dec_reset),
(theora_dec_push_forward), (theora_dec_push_reverse),
(theora_handle_data_packet), (theora_dec_decode_buffer),
(theora_dec_flush_decode), (theora_dec_chain_reverse),
(theora_dec_chain_forward), (theora_dec_chain):
Implement reverse playback.
* ext/vorbis/vorbisdec.c: (gst_vorbis_dec_reset),
(vorbis_dec_decode_buffer), (vorbis_dec_flush_decode),
(vorbis_dec_chain_forward):
Clear buffers used for reverse playback in _reset.
No need to set the eos flag, we clip samples using the segment.

ChangeLog
ext/theora/theoradec.c
ext/vorbis/vorbisdec.c

index b871fa6..761f66c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2006-11-26  Wim Taymans  <wim@fluendo.com>
+
+       * ext/theora/theoradec.c: (gst_theora_dec_reset),
+       (theora_dec_push_forward), (theora_dec_push_reverse),
+       (theora_handle_data_packet), (theora_dec_decode_buffer),
+       (theora_dec_flush_decode), (theora_dec_chain_reverse),
+       (theora_dec_chain_forward), (theora_dec_chain):
+       Implement reverse playback.
+
+       * ext/vorbis/vorbisdec.c: (gst_vorbis_dec_reset),
+       (vorbis_dec_decode_buffer), (vorbis_dec_flush_decode),
+       (vorbis_dec_chain_forward):
+       Clear buffers used for reverse playback in _reset.
+       No need to set the eos flag, we clip samples using the segment.
+
 2006-11-24  Wim Taymans  <wim@fluendo.com>
 
        * ext/ogg/gstoggdemux.c: (gst_ogg_page_copy), (gst_ogg_page_free),
index 72f6913..88bd299 100644 (file)
@@ -171,8 +171,6 @@ gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class)
 static void
 gst_theora_dec_reset (GstTheoraDec * dec)
 {
-  GList *walk;
-
   dec->need_keyframe = TRUE;
   dec->last_timestamp = -1;
   dec->granulepos = -1;
@@ -185,11 +183,15 @@ gst_theora_dec_reset (GstTheoraDec * dec)
   dec->earliest_time = -1;
   GST_OBJECT_UNLOCK (dec);
 
-  for (walk = dec->queued; walk; walk = g_list_next (walk)) {
-    gst_buffer_unref (GST_BUFFER_CAST (walk->data));
-  }
+  g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
   g_list_free (dec->queued);
   dec->queued = NULL;
+  g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (dec->gather);
+  dec->gather = NULL;
+  g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (dec->decode);
+  dec->decode = NULL;
 }
 
 static int
@@ -902,7 +904,7 @@ beach:
 
 /* FIXME, this needs to be moved to the demuxer */
 static GstFlowReturn
-theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
+theora_dec_push_forward (GstTheoraDec * dec, GstBuffer * buf)
 {
   GstFlowReturn result = GST_FLOW_OK;
   GstClockTime outtime = GST_BUFFER_TIMESTAMP (buf);
@@ -952,6 +954,15 @@ theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
     else
       gst_buffer_unref (buf);
   }
+  return result;
+}
+
+static GstFlowReturn
+theora_dec_push_reverse (GstTheoraDec * dec, GstBuffer * buf)
+{
+  GstFlowReturn result = GST_FLOW_OK;
+
+  dec->queued = g_list_prepend (dec->queued, buf);
 
   return result;
 }
@@ -1091,7 +1102,10 @@ theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
       dec->info.fps_numerator);
   GST_BUFFER_TIMESTAMP (out) = outtime;
 
-  result = theora_dec_push (dec, out);
+  if (dec->segment.rate >= 0.0)
+    result = theora_dec_push_forward (dec, out);
+  else
+    result = theora_dec_push_reverse (dec, out);
 
   return result;
 
@@ -1143,20 +1157,11 @@ no_buffer:
 }
 
 static GstFlowReturn
-theora_dec_chain_forward (GstTheoraDec * dec, gboolean discont, GstBuffer * buf)
+theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf)
 {
   ogg_packet packet;
   GstFlowReturn result = GST_FLOW_OK;
 
-  /* resync on DISCONT */
-  if (G_UNLIKELY (discont)) {
-    GST_DEBUG_OBJECT (dec, "received DISCONT buffer");
-    dec->need_keyframe = TRUE;
-    dec->last_timestamp = -1;
-    dec->granulepos = -1;
-    dec->discont = TRUE;
-  }
-
   /* make ogg_packet out of the buffer */
   packet.packet = GST_BUFFER_DATA (buf);
   packet.bytes = GST_BUFFER_SIZE (buf);
@@ -1199,8 +1204,6 @@ done:
   /* interpolate granule pos */
   dec->granulepos = _inc_granulepos (dec, dec->granulepos);
 
-  gst_buffer_unref (buf);
-
   return result;
 }
 
@@ -1297,7 +1300,13 @@ theora_dec_flush_decode (GstTheoraDec * dec)
   while (dec->decode) {
     GstBuffer *buf = GST_BUFFER_CAST (dec->decode->data);
 
-    /* FIXME, decode buffer, prepend to output queue */
+    GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT,
+        buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+    /* decode buffer, prepend to output queue */
+    res = theora_dec_decode_buffer (dec, buf);
+
+    /* don't need it anymore now */
     gst_buffer_unref (buf);
 
     dec->decode = g_list_delete_link (dec->decode, dec->decode);
@@ -1320,31 +1329,49 @@ theora_dec_chain_reverse (GstTheoraDec * dec, gboolean discont, GstBuffer * buf)
   GstFlowReturn res = GST_FLOW_OK;
 
   /* if we have a discont, move buffers to the decode list */
-  if (discont) {
+  if (G_UNLIKELY (discont)) {
+    GST_DEBUG_OBJECT (dec, "received discont,gathering buffers");
     while (dec->gather) {
-      GstBuffer *buf;
+      GstBuffer *gbuf;
       guint8 *data;
 
-      buf = GST_BUFFER_CAST (dec->gather->data);
+      gbuf = GST_BUFFER_CAST (dec->gather->data);
       /* remove from the gather list */
       dec->gather = g_list_delete_link (dec->gather, dec->gather);
       /* copy to decode queue */
-      dec->decode = g_list_prepend (dec->decode, buf);
+      dec->decode = g_list_prepend (dec->decode, gbuf);
 
       /* if we copied a keyframe, flush and decode the decode queue */
-      data = GST_BUFFER_DATA (buf);
-      if ((data[0] & 0x40) == 0)
+      data = GST_BUFFER_DATA (gbuf);
+      if ((data[0] & 0x40) == 0) {
+        GST_DEBUG_OBJECT (dec, "copied keyframe");
         res = theora_dec_flush_decode (dec);
+      }
     }
   }
 
   /* add buffer to gather queue */
+  GST_DEBUG_OBJECT (dec, "gathering buffer %p, size %u", buf,
+      GST_BUFFER_SIZE (buf));
   dec->gather = g_list_prepend (dec->gather, buf);
 
   return res;
 }
 
 static GstFlowReturn
+theora_dec_chain_forward (GstTheoraDec * dec, gboolean discont,
+    GstBuffer * buffer)
+{
+  GstFlowReturn result;
+
+  result = theora_dec_decode_buffer (dec, buffer);
+
+  gst_buffer_unref (buffer);
+
+  return result;
+}
+
+static GstFlowReturn
 theora_dec_chain (GstPad * pad, GstBuffer * buf)
 {
   GstTheoraDec *dec;
@@ -1356,6 +1383,15 @@ theora_dec_chain (GstPad * pad, GstBuffer * buf)
   /* peel of DISCONT flag */
   discont = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT);
 
+  /* resync on DISCONT */
+  if (G_UNLIKELY (discont)) {
+    GST_DEBUG_OBJECT (dec, "received DISCONT buffer");
+    dec->need_keyframe = TRUE;
+    dec->last_timestamp = -1;
+    dec->granulepos = -1;
+    dec->discont = TRUE;
+  }
+
   if (dec->segment.rate > 0.0)
     res = theora_dec_chain_forward (dec, discont, buf);
   else
index 1fd5b63..678bd47 100644 (file)
@@ -189,23 +189,22 @@ vorbis_dec_finalize (GObject * object)
 static void
 gst_vorbis_dec_reset (GstVorbisDec * dec)
 {
-  GList *walk;
-
   dec->cur_timestamp = GST_CLOCK_TIME_NONE;
   dec->prev_timestamp = GST_CLOCK_TIME_NONE;
   dec->granulepos = -1;
   dec->discont = TRUE;
   gst_segment_init (&dec->segment, GST_FORMAT_TIME);
 
-  for (walk = dec->queued; walk; walk = g_list_next (walk)) {
-    gst_buffer_unref (GST_BUFFER_CAST (walk->data));
-  }
+  g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
   g_list_free (dec->queued);
   dec->queued = NULL;
-
-  for (walk = dec->pendingevents; walk; walk = g_list_next (walk)) {
-    gst_event_unref (GST_EVENT_CAST (walk->data));
-  }
+  g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (dec->gather);
+  dec->gather = NULL;
+  g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (dec->decode);
+  dec->decode = NULL;
+  g_list_foreach (dec->pendingevents, (GFunc) gst_mini_object_unref, NULL);
   g_list_free (dec->pendingevents);
   dec->pendingevents = NULL;
 
@@ -1071,7 +1070,7 @@ wrong_samples:
 }
 
 static GstFlowReturn
-vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer, gboolean eos)
+vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer)
 {
   ogg_packet packet;
   GstFlowReturn result = GST_FLOW_OK;
@@ -1105,7 +1104,7 @@ vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer, gboolean eos)
    * Yes there is, keep one packet at all times and only push out when
    * you receive a new one.  Implement this.
    */
-  packet.e_o_s = (eos ? 1 : 0);
+  packet.e_o_s = 0;
 
   if (G_UNLIKELY (packet.bytes < 1))
     goto wrong_size;
@@ -1220,7 +1219,7 @@ vorbis_dec_flush_decode (GstVorbisDec * dec)
     next = g_list_next (walk);
 
     /* decode buffer, prepend to output queue */
-    res = vorbis_dec_decode_buffer (dec, buf, next == NULL);
+    res = vorbis_dec_decode_buffer (dec, buf);
 
     /* if we generated output, we can discard the buffer, else we
      * keep it in the queue */
@@ -1282,7 +1281,6 @@ vorbis_dec_flush_decode (GstVorbisDec * dec)
   } else {
     GST_DEBUG_OBJECT (dec, "we don't have a granulepos yet, delayed push");
   }
-
   return res;
 }
 
@@ -1321,7 +1319,7 @@ vorbis_dec_chain_forward (GstVorbisDec * vd, gboolean discont,
 {
   GstFlowReturn result;
 
-  result = vorbis_dec_decode_buffer (vd, buffer, FALSE);
+  result = vorbis_dec_decode_buffer (vd, buffer);
 
   gst_buffer_unref (buffer);