ext/faad/gstfaad.*: Add basic reverse playback support.
authorWim Taymans <wim.taymans@gmail.com>
Mon, 2 Jun 2008 10:18:25 +0000 (10:18 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Mon, 2 Jun 2008 10:18:25 +0000 (10:18 +0000)
Original commit message from CVS:
* ext/faad/gstfaad.c: (gst_faad_dispose), (clear_queued),
(flush_queued), (gst_faad_drain), (gst_faad_do_raw_seek),
(gst_faad_src_event), (gst_faad_sink_event), (gst_faad_chain),
(gst_faad_change_state):
* ext/faad/gstfaad.h:
Add basic reverse playback support.
Clear decoder state after disconts.
Remove some unused code.
Mark output buffers with a discont after a decoding error.

ChangeLog
ext/faad/gstfaad.c
ext/faad/gstfaad.h

index e82304f..fa88750 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2008-06-02  Wim Taymans  <wim.taymans@collabora.co.uk>
+
+       * ext/faad/gstfaad.c: (gst_faad_dispose), (clear_queued),
+       (flush_queued), (gst_faad_drain), (gst_faad_do_raw_seek),
+       (gst_faad_src_event), (gst_faad_sink_event), (gst_faad_chain),
+       (gst_faad_change_state):
+       * ext/faad/gstfaad.h:
+       Add basic reverse playback support.
+       Clear decoder state after disconts.
+       Remove some unused code.
+       Mark output buffers with a discont after a decoding error.
+
 2008-06-02  Sebastian Dröge  <slomo@circular-chaos.org>
 
        Patch by: Sjoerd Simons <sjoerd at luon dot net>
index a65550d..178ff64 100644 (file)
@@ -246,7 +246,6 @@ gst_faad_dispose (GObject * object)
   }
 
   G_OBJECT_CLASS (parent_class)->dispose (object);
-
 }
 
 static void
@@ -757,6 +756,48 @@ gst_faad_srcconnect (GstPad * pad, const GstCaps * caps)
   return GST_PAD_LINK_REFUSED;
 }*/
 
+static void
+clear_queued (GstFaad * faad)
+{
+  g_list_foreach (faad->queued, (GFunc) gst_mini_object_unref, NULL);
+  g_list_free (faad->queued);
+  faad->queued = NULL;
+}
+
+static GstFlowReturn
+flush_queued (GstFaad * faad)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  while (faad->queued) {
+    GstBuffer *buf = GST_BUFFER_CAST (faad->queued->data);
+
+    GST_LOG_OBJECT (faad, "pushing buffer %p, timestamp %"
+        GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf,
+        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+        GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
+
+    /* iterate ouput queue an push downstream */
+    ret = gst_pad_push (faad->srcpad, buf);
+
+    faad->queued = g_list_delete_link (faad->queued, faad->queued);
+  }
+  return ret;
+}
+
+static GstFlowReturn
+gst_faad_drain (GstFaad * faad)
+{
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  if (faad->segment->rate < 0.0) {
+    /* if we have some queued frames for reverse playback, flush
+     * them now */
+    ret = flush_queued (faad);
+  }
+  return ret;
+}
+
 static gboolean
 gst_faad_do_raw_seek (GstFaad * faad, GstEvent * event)
 {
@@ -786,7 +827,7 @@ gst_faad_do_raw_seek (GstFaad * faad, GstEvent * event)
   GST_DEBUG_OBJECT (faad, "seeking to %" GST_TIME_FORMAT " at byte offset %"
       G_GINT64_FORMAT, GST_TIME_ARGS (start_time), start);
 
-  return gst_pad_send_event (GST_PAD_PEER (faad->sinkpad), event);
+  return gst_pad_push_event (faad->sinkpad, event);
 }
 
 static gboolean
@@ -803,14 +844,14 @@ gst_faad_src_event (GstPad * pad, GstEvent * event)
     case GST_EVENT_SEEK:{
       /* try upstream first, there might be a demuxer */
       gst_event_ref (event);
-      if (!(res = gst_pad_event_default (pad, event))) {
+      if (!(res = gst_pad_push_event (faad->sinkpad, event))) {
         res = gst_faad_do_raw_seek (faad, event);
       }
       gst_event_unref (event);
       break;
     }
     default:
-      res = gst_pad_event_default (pad, event);
+      res = gst_pad_push_event (faad->sinkpad, event);
       break;
   }
 
@@ -828,9 +869,17 @@ gst_faad_sink_event (GstPad * pad, GstEvent * event)
 
   GST_LOG_OBJECT (faad, "Handling %s event", GST_EVENT_TYPE_NAME (event));
 
-  /* FIXME: we should probably handle FLUSH */
   switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP:
+      if (faad->tempbuf != NULL) {
+        gst_buffer_unref (faad->tempbuf);
+        faad->tempbuf = NULL;
+      }
+      clear_queued (faad);
+      res = gst_pad_push_event (faad->srcpad, event);
+      break;
     case GST_EVENT_EOS:
+      gst_faad_drain (faad);
       if (faad->tempbuf != NULL) {
         gst_buffer_unref (faad->tempbuf);
         faad->tempbuf = NULL;
@@ -846,6 +895,7 @@ gst_faad_sink_event (GstPad * pad, GstEvent * event)
 
       gst_event_parse_new_segment (event, &is_update, &rate, &fmt, &start,
           &end, &base);
+
       if (fmt == GST_FORMAT_TIME) {
         GST_DEBUG ("Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
             GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
@@ -871,6 +921,9 @@ gst_faad_sink_event (GstPad * pad, GstEvent * event)
         }
         gst_event_unref (event);
 
+        /* drain queued buffers before we activate the new segment */
+        gst_faad_drain (faad);
+
         event = gst_event_new_new_segment (is_update, rate,
             GST_FORMAT_TIME, new_start, new_end, new_start);
 
@@ -1173,6 +1226,16 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
 
   faad = GST_FAAD (gst_pad_get_parent (pad));
 
+  if (GST_BUFFER_IS_DISCONT (buffer)) {
+    gst_faad_drain (faad);
+    faacDecPostSeekReset (faad->handle, 0);
+    if (faad->tempbuf != NULL) {
+      gst_buffer_unref (faad->tempbuf);
+      faad->tempbuf = NULL;
+    }
+    faad->discont = TRUE;
+  }
+
   GST_OBJECT_LOCK (faad);
   faad->bytes_in += GST_BUFFER_SIZE (buffer);
   GST_OBJECT_UNLOCK (faad);
@@ -1264,47 +1327,11 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
         input_size - skip_bytes);
 
     if (info.error > 0) {
-      guint32 rate;
-      guint8 ch;
-
-      GST_DEBUG_OBJECT (faad, "decoding error: %s",
+      GST_WARNING_OBJECT (faad, "decoding error: %s",
           faacDecGetErrorMessage (info.error));
-
+      /* mark discont for the next buffer */
+      faad->discont = TRUE;
       goto out;
-
-      if (!faad->packetised)
-        goto decode_error;
-
-      /* decode error? try again using faacDecInit2 
-       * fabricated private codec data from sink caps */
-      gst_faad_close_decoder (faad);
-      if (!gst_faad_open_decoder (faad))
-        goto init2_failed;
-
-      GST_DEBUG_OBJECT (faad, "decoding error, reopening with faacDecInit2()");
-      if ((gint8) faacDecInit2 (faad->handle, faad->fake_codec_data, 2,
-              &rate, &ch) < 0) {
-        goto init2_failed;
-      }
-
-      GST_DEBUG_OBJECT (faad, "faacDecInit2(): rate=%d,channels=%d", rate, ch);
-
-      /* let's try again */
-      info.error = 0;
-      out = faacDecDecode (faad->handle, &info, input_data + skip_bytes,
-          input_size - skip_bytes);
-
-      if (info.error) {
-        faad->error_count++;
-        if (faad->error_count >= MAX_DECODE_ERRORS)
-          goto decode_error;
-        GST_DEBUG_OBJECT (faad,
-            "Failed to decode buffer: %s, count = %d, trying to resync",
-            faacDecGetErrorMessage (info.error), faad->error_count);
-        continue;
-      }
-
-      faad->error_count = 0;    /* all fine, reset error counter */
     }
 
     if (info.bytesconsumed > input_size)
@@ -1378,7 +1405,20 @@ gst_faad_chain (GstPad * pad, GstBuffer * buffer)
               "pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%" GST_TIME_FORMAT,
               GST_BUFFER_OFFSET (outbuf),
               GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
-          ret = gst_pad_push (faad->srcpad, outbuf);
+
+          if (faad->discont) {
+            GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+            faad->discont = FALSE;
+          }
+
+          if (faad->segment->rate > 0.0) {
+            ret = gst_pad_push (faad->srcpad, outbuf);
+          } else {
+            /* reverse playback, queue frame till later when we get a discont. */
+            GST_DEBUG_OBJECT (faad, "queued frame");
+            faad->queued = g_list_prepend (faad->queued, outbuf);
+            ret = GST_FLOW_OK;
+          }
           if (ret != GST_FLOW_OK)
             goto out;
         }
@@ -1421,13 +1461,6 @@ init2_failed:
     ret = GST_FLOW_ERROR;
     goto out;
   }
-decode_error:
-  {
-    GST_ELEMENT_ERROR (faad, STREAM, DECODE, (NULL),
-        ("Failed to decode buffer: %s", faacDecGetErrorMessage (info.error)));
-    ret = GST_FLOW_ERROR;
-    goto out;
-  }
 }
 
 static gboolean
@@ -1498,13 +1531,14 @@ gst_faad_change_state (GstElement * element, GstStateChange transition)
       faad->bytes_in = 0;
       faad->sum_dur_out = 0;
       faad->error_count = 0;
-      break;
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      gst_faad_close_decoder (faad);
       if (faad->tempbuf) {
         gst_buffer_unref (faad->tempbuf);
         faad->tempbuf = NULL;
       }
+      clear_queued (faad);
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_faad_close_decoder (faad);
       break;
     default:
       break;
index 7c20a01..fd989b6 100644 (file)
@@ -68,9 +68,16 @@ typedef struct _GstFaad {
   guint64 bytes_in;    /* bytes received                                  */
   guint64 sum_dur_out; /* sum of durations of decoded buffers we sent out */
   gint    error_count;
+  gboolean discont;
 
   /* segment handling */
   GstSegment * segment;
+
+  /* list of raw output buffers for reverse playback */
+  GList *queued;
+  /* gather/decode queues for reverse playback */
+  GList *gather;
+  GList *decode;
 } GstFaad;
 
 typedef struct _GstFaadClass {