tta plugin ported to 0.9
authorArwed v. Merkatz <v.merkatz@gmx.net>
Thu, 22 Sep 2005 11:17:26 +0000 (11:17 +0000)
committerArwed v. Merkatz <v.merkatz@gmx.net>
Thu, 22 Sep 2005 11:17:26 +0000 (11:17 +0000)
Original commit message from CVS:
tta plugin ported to 0.9

ChangeLog
configure.ac
gst/tta/gstttadec.c
gst/tta/gstttaparse.c
gst/tta/gstttaparse.h

index 137a66b..4285027 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2005-09-22  Arwed v. Merkatz  <v.merkatz@gmx.net>
+
+       * configure.ac:
+       * gst/tta/gstttadec.c: (gst_tta_dec_setcaps), (gst_tta_dec_init),
+       (gst_tta_dec_chain):
+       * gst/tta/gstttaparse.c: (gst_tta_parse_dispose),
+       (gst_tta_parse_class_init), (gst_tta_parse_reset),
+       (gst_tta_parse_init), (gst_tta_parse_src_event),
+       (gst_tta_parse_get_query_types), (gst_tta_parse_query),
+       (gst_tta_parse_activate), (gst_tta_parse_activate_pull),
+       (gst_tta_parse_parse_header), (gst_tta_parse_stream_data),
+       (gst_tta_parse_loop), (gst_tta_parse_change_state):
+       * gst/tta/gstttaparse.h:
+         Ported tta plugin to 0.9.
+
 
 2005-09-20  Flavio Oliveira  <flavio.oliveira@indt.org.br>
 
index 0bea354..74d5d24 100644 (file)
@@ -287,6 +287,7 @@ AC_SUBST(GST_PLUGIN_LDFLAGS)
 dnl these are all the gst plug-ins, compilable without additional libs
 GST_PLUGINS_ALL="\
                qtdemux \
+               tta     \
                 "
 
 dnl see if we can build C++ plug-ins
@@ -466,6 +467,7 @@ gst-plugins-bad.spec
 gst/Makefile
 gst/qtdemux/Makefile
 gst/speed/Makefile
+gst/tta/Makefile
 sys/Makefile
 ext/Makefile
 ext/faac/Makefile
index c550e7c..9f36ffc 100644 (file)
@@ -96,24 +96,27 @@ static void gst_tta_dec_class_init (GstTtaDecClass * klass);
 static void gst_tta_dec_base_init (GstTtaDecClass * klass);
 static void gst_tta_dec_init (GstTtaDec * ttadec);
 
-static void gst_tta_dec_chain (GstPad * pad, GstData * in);
+static GstFlowReturn gst_tta_dec_chain (GstPad * pad, GstBuffer * in);
 
 static GstElementClass *parent = NULL;
 
-static GstPadLinkReturn
-gst_tta_dec_link (GstPad * pad, const GstCaps * caps)
+static gboolean
+gst_tta_dec_setcaps (GstPad * pad, GstCaps * caps)
 {
   GstTtaDec *ttadec = GST_TTA_DEC (gst_pad_get_parent (pad));
   GstStructure *structure = gst_caps_get_structure (caps, 0);
   GstCaps *srccaps;
   guint64 outsize;
-  guint bits;
+  gint bits, channels;
+  gint32 samplerate;
 
-  if (!gst_caps_is_fixed (caps))
-    return GST_PAD_LINK_DELAYED;
+//  if (!gst_caps_is_fixed (caps))
+//    return GST_PAD_LINK_DELAYED;
 
-  gst_structure_get_int (structure, "rate", &ttadec->samplerate);
-  gst_structure_get_int (structure, "channels", &ttadec->channels);
+  gst_structure_get_int (structure, "rate", &samplerate);
+  ttadec->samplerate = (guint32) samplerate;
+  gst_structure_get_int (structure, "channels", &channels);
+  ttadec->channels = (guint) channels;
   gst_structure_get_int (structure, "width", &bits);
   ttadec->bytes = bits / 8;
 
@@ -125,7 +128,8 @@ gst_tta_dec_link (GstPad * pad, const GstCaps * caps)
       "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
       "signed", G_TYPE_BOOLEAN, TRUE, NULL);
 
-  gst_pad_set_explicit_caps (ttadec->srcpad, srccaps);
+  if (!gst_pad_set_caps (ttadec->srcpad, srccaps))
+    return FALSE;
 
   ttadec->frame_length = FRAME_TIME * ttadec->samplerate;
 
@@ -138,7 +142,7 @@ gst_tta_dec_link (GstPad * pad, const GstCaps * caps)
       (guchar *) g_malloc (ttadec->channels * ttadec->frame_length *
       ttadec->bytes * sizeof (guchar));
 
-  return GST_PAD_LINK_OK;
+  return TRUE;
 }
 
 GType
@@ -216,19 +220,18 @@ gst_tta_dec_init (GstTtaDec * ttadec)
   ttadec->sinkpad =
       gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
           "sink"), "sink");
-  gst_pad_set_link_function (ttadec->sinkpad, gst_tta_dec_link);
+  gst_pad_set_setcaps_function (ttadec->sinkpad, gst_tta_dec_setcaps);
 
   ttadec->srcpad =
       gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
           "src"), "src");
-  gst_pad_use_explicit_caps (ttadec->srcpad);
+  gst_pad_use_fixed_caps (ttadec->srcpad);
 
   gst_element_add_pad (GST_ELEMENT (ttadec), ttadec->sinkpad);
   gst_element_add_pad (GST_ELEMENT (ttadec), ttadec->srcpad);
   gst_pad_set_chain_function (ttadec->sinkpad, gst_tta_dec_chain);
   ttadec->tta_buf.buffer = (guchar *) g_malloc (TTA_BUFFER_SIZE + 4);
   ttadec->tta_buf.buffer_end = ttadec->tta_buf.buffer + TTA_BUFFER_SIZE;
-  GST_FLAG_SET (ttadec, GST_ELEMENT_EVENT_AWARE);
 }
 
 void
@@ -311,8 +314,8 @@ get_unary (tta_buffer * tta_buf, guchar * buffer, unsigned long buffersize,
   tta_buf->bit_count--;
 }
 
-static void
-gst_tta_dec_chain (GstPad * pad, GstData * in)
+static GstFlowReturn
+gst_tta_dec_chain (GstPad * pad, GstBuffer * in)
 {
   GstTtaDec *ttadec;
   GstBuffer *outbuf, *buf = GST_BUFFER (in);
@@ -324,16 +327,8 @@ gst_tta_dec_chain (GstPad * pad, GstData * in)
   long res;
   long *prev;
 
-  g_return_if_fail (GST_IS_PAD (pad));
-  g_return_if_fail (buf != NULL);
-
   ttadec = GST_TTA_DEC (GST_OBJECT_PARENT (pad));
-  g_return_if_fail (GST_IS_TTA_DEC (ttadec));
 
-  if (GST_IS_EVENT (buf)) {
-    gst_pad_event_default (pad, GST_EVENT (buf));
-    return;
-  }
   data = GST_BUFFER_DATA (buf);
   size = GST_BUFFER_SIZE (buf);
 
@@ -447,7 +442,8 @@ gst_tta_dec_chain (GstPad * pad, GstData * in)
   memcpy (GST_BUFFER_DATA (outbuf), ttadec->decdata, outsize);
   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
-  gst_pad_push (ttadec->srcpad, GST_DATA (outbuf));
+  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ttadec->srcpad));
+  return gst_pad_push (ttadec->srcpad, outbuf);
 }
 
 gboolean
index 3509d35..f45f4c1 100644 (file)
 GST_DEBUG_CATEGORY_STATIC (gst_tta_parse_debug);
 #define GST_CAT_DEFAULT gst_tta_parse_debug
 
-/* Filter signals and args */
-enum
-{
-  LAST_SIGNAL
-};
-
-enum
-{
-  ARG_0
-};
-
 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
@@ -59,9 +48,16 @@ static void gst_tta_parse_class_init (GstTtaParseClass * klass);
 static void gst_tta_parse_base_init (GstTtaParseClass * klass);
 static void gst_tta_parse_init (GstTtaParse * ttaparse);
 
-static void gst_tta_parse_chain (GstPad * pad, GstData * in);
+static gboolean gst_tta_parse_src_event (GstPad * pad, GstEvent * event);
+static const GstQueryType *gst_tta_parse_get_query_types (GstPad * pad);
+static gboolean gst_tta_parse_query (GstPad * pad, GstQuery * query);
+static gboolean gst_tta_parse_activate (GstPad * pad);
+static gboolean gst_tta_parse_activate_pull (GstPad * pad, gboolean active);
+static void gst_tta_parse_loop (GstTtaParse * ttaparse);
+static GstStateChangeReturn gst_tta_parse_change_state (GstElement * element,
+    GstStateChange transition);
 
-static GstElementClass *parent = NULL;
+static GstElementClass *parent_class = NULL;
 
 GType
 gst_tta_parse_get_type (void)
@@ -111,7 +107,7 @@ gst_tta_parse_dispose (GObject * object)
 
   g_free (ttaparse->index);
 
-  G_OBJECT_CLASS (parent)->dispose (object);
+  G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
 static void
@@ -123,287 +119,362 @@ gst_tta_parse_class_init (GstTtaParseClass * klass)
   gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
 
-  parent = g_type_class_ref (GST_TYPE_ELEMENT);
+  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
 
   gobject_class->dispose = gst_tta_parse_dispose;
+  gstelement_class->change_state = gst_tta_parse_change_state;
 }
 
-static gboolean
-gst_tta_src_query (GstPad * pad, GstQueryType type,
-    GstFormat * format, gint64 * value)
+static void
+gst_tta_parse_reset (GstTtaParse * ttaparse)
 {
-  GstTtaParse *ttaparse = GST_TTA_PARSE (gst_pad_get_parent (pad));
+  ttaparse->header_parsed = FALSE;
+  ttaparse->current_frame = 0;
+  ttaparse->data_length = 0;
+  ttaparse->samplerate = 0;
+}
 
-  if (type == GST_QUERY_TOTAL) {
-    if (*format == GST_FORMAT_TIME) {
-      if ((ttaparse->data_length == 0) || (ttaparse->samplerate == 0)) {
-        *value = 0;
-        return FALSE;
-      }
-      *value =
-          ((gdouble) ttaparse->data_length / (gdouble) ttaparse->samplerate) *
-          GST_SECOND;
-      GST_DEBUG_OBJECT (ttaparse, "got queried for time, returned %lli",
-          *value);
-      return TRUE;
-    }
-  } else {
-    return gst_pad_query_default (pad, type, format, value);
-  }
-  return FALSE;
+static void
+gst_tta_parse_init (GstTtaParse * ttaparse)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (ttaparse);
+
+  ttaparse->sinkpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "sink"), "sink");
+
+  ttaparse->srcpad =
+      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+          "src"), "src");
+  gst_pad_use_fixed_caps (ttaparse->srcpad);
+  gst_pad_set_query_type_function (ttaparse->srcpad,
+      gst_tta_parse_get_query_types);
+  gst_pad_set_query_function (ttaparse->srcpad, gst_tta_parse_query);
+  gst_pad_set_event_function (ttaparse->srcpad, gst_tta_parse_src_event);
+
+  gst_element_add_pad (GST_ELEMENT (ttaparse), ttaparse->sinkpad);
+  gst_element_add_pad (GST_ELEMENT (ttaparse), ttaparse->srcpad);
+  gst_pad_set_activate_function (ttaparse->sinkpad, gst_tta_parse_activate);
+  gst_pad_set_activatepull_function (ttaparse->sinkpad,
+      gst_tta_parse_activate_pull);
+
+  gst_tta_parse_reset (ttaparse);
 }
 
 static gboolean
-gst_tta_src_event (GstPad * pad, GstEvent * event)
+gst_tta_parse_src_event (GstPad * pad, GstEvent * event)
 {
-  GstTtaParse *ttaparse = GST_TTA_PARSE (gst_pad_get_parent (pad));
+  GstTtaParse *ttaparse = GST_TTA_PARSE (GST_PAD_PARENT (pad));
+
+  gboolean res = TRUE;
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
     {
-      if (GST_EVENT_SEEK_FORMAT (event) == GST_FORMAT_TIME) {
-        GstEvent *seek_event;
-        guint64 time;
-        guint64 seek_frame;
-        guint64 seekpos;
-
-        time = GST_EVENT_SEEK_OFFSET (event);
-        seek_frame = time / (FRAME_TIME * 1000000000);
-        seekpos = ttaparse->index[seek_frame].pos;
-
-        GST_DEBUG_OBJECT (ttaparse, "seeking to %u", (guint) seekpos);
-        seek_event =
-            gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET |
-            GST_SEEK_FLAG_ACCURATE, seekpos);
-        gst_event_unref (event);
-        if (gst_pad_send_event (GST_PAD_PEER (ttaparse->sinkpad), seek_event)) {
-          gst_pad_event_default (ttaparse->srcpad,
-              gst_event_new (GST_EVENT_FLUSH));
-          return TRUE;
+      gdouble rate;
+      GstFormat format;
+      GstSeekFlags flags;
+      GstSeekType start_type, stop_type;
+      gint64 start, stop;
+
+      gst_event_parse_seek (event, &rate, &format, &flags,
+          &start_type, &start, &stop_type, &stop);
+
+      if (format == GST_FORMAT_TIME) {
+        if (flags & GST_SEEK_FLAG_FLUSH) {
+          gst_pad_push_event (ttaparse->srcpad, gst_event_new_flush_start ());
+          gst_pad_push_event (ttaparse->sinkpad, gst_event_new_flush_start ());
         } else {
-          GST_LOG_OBJECT (ttaparse, "seek failed");
-          return FALSE;
+          gst_pad_pause_task (ttaparse->sinkpad);
+        }
+        GST_STREAM_LOCK (ttaparse->sinkpad);
+
+        switch (start_type) {
+          case GST_SEEK_TYPE_CUR:
+            ttaparse->current_frame += (start / GST_SECOND) / FRAME_TIME;
+            break;
+          case GST_SEEK_TYPE_END:
+            ttaparse->current_frame += (start / GST_SECOND) / FRAME_TIME;
+            break;
+          case GST_SEEK_TYPE_SET:
+            ttaparse->current_frame = (start / GST_SECOND) / FRAME_TIME;
+            break;
+          case GST_SEEK_TYPE_NONE:
+            break;
+        }
+        res = TRUE;
+
+        if (flags & GST_SEEK_FLAG_FLUSH) {
+          gst_pad_push_event (ttaparse->srcpad, gst_event_new_flush_stop ());
+          gst_pad_push_event (ttaparse->sinkpad, gst_event_new_flush_stop ());
         }
+
+        gst_pad_push_event (ttaparse->srcpad, gst_event_new_newsegment (1.0,
+                GST_FORMAT_TIME, 0,
+                ttaparse->num_frames * FRAME_TIME * GST_SECOND, 0));
+
+        gst_pad_start_task (ttaparse->sinkpad,
+            (GstTaskFunction) gst_tta_parse_loop, ttaparse);
+
+        GST_STREAM_UNLOCK (ttaparse->sinkpad);
+
       } else {
-        return gst_pad_send_event (pad, event);
+        res = FALSE;
       }
+
+      gst_event_unref (event);
       break;
     }
     default:
-      return gst_pad_send_event (pad, event);
+      res = gst_pad_event_default (pad, event);
       break;
   }
+
+  return res;
 }
 
-static void
-gst_tta_parse_init (GstTtaParse * ttaparse)
+static const GstQueryType *
+gst_tta_parse_get_query_types (GstPad * pad)
 {
-  GstElementClass *klass = GST_ELEMENT_GET_CLASS (ttaparse);
-
-  ttaparse->sinkpad =
-      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
-          "sink"), "sink");
-
-  ttaparse->srcpad =
-      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
-          "src"), "src");
-  gst_pad_use_explicit_caps (ttaparse->srcpad);
-  gst_pad_set_query_function (ttaparse->srcpad, gst_tta_src_query);
-  gst_pad_set_event_function (ttaparse->srcpad, gst_tta_src_event);
-
-  gst_element_add_pad (GST_ELEMENT (ttaparse), ttaparse->sinkpad);
-  gst_element_add_pad (GST_ELEMENT (ttaparse), ttaparse->srcpad);
-  gst_pad_set_chain_function (ttaparse->sinkpad, gst_tta_parse_chain);
-
-  ttaparse->silent = FALSE;
-  ttaparse->header_parsed = FALSE;
-  ttaparse->partialbuf = NULL;
-  ttaparse->seek_ok = FALSE;
-  ttaparse->current_frame = 0;
-  ttaparse->data_length = 0;
-  ttaparse->samplerate = 0;
+  static const GstQueryType types[] = {
+    GST_QUERY_POSITION,
+    0
+  };
 
-  GST_FLAG_SET (ttaparse, GST_ELEMENT_EVENT_AWARE);
+  return types;
 }
 
-static void
-gst_tta_handle_event (GstPad * pad, GstBuffer * buffer)
+static gboolean
+gst_tta_parse_query (GstPad * pad, GstQuery * query)
 {
-  GstEvent *event = GST_EVENT (buffer);
   GstTtaParse *ttaparse = GST_TTA_PARSE (gst_pad_get_parent (pad));
 
-  GST_DEBUG_OBJECT (ttaparse, "got some event");
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_DISCONTINUOUS:
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:
     {
-      GstEvent *discont;
-      guint64 offset = GST_EVENT_DISCONT_OFFSET (event, 0).value;
-      int i;
-
-      GST_DEBUG_OBJECT (ttaparse, "discont with offset: %u", offset);
-      for (i = 0; i < ttaparse->num_frames; i++) {
-        if (offset == ttaparse->index[i].pos) {
-          GST_DEBUG_OBJECT (ttaparse, "setting current frame to %i", i);
-          discont = gst_event_new_discontinuous (FALSE,
-              GST_FORMAT_TIME, ttaparse->index[i].time, NULL);
-          gst_event_unref (event);
-          gst_buffer_unref (ttaparse->partialbuf);
-          ttaparse->partialbuf = NULL;
-          ttaparse->current_frame = i;
-          gst_pad_event_default (pad, gst_event_new (GST_EVENT_FLUSH));
-          gst_pad_event_default (pad, discont);
-          GST_DEBUG_OBJECT (ttaparse, "sent discont event");
-          return;
-        }
+      GstFormat format;
+      gint64 cur, end;
+
+      gst_query_parse_position (query, &format, NULL, NULL);
+      switch (format) {
+        case GST_FORMAT_TIME:
+          cur = ttaparse->index[ttaparse->current_frame].time;
+          end = ((gdouble) ttaparse->data_length /
+              (gdouble) ttaparse->samplerate) * GST_SECOND;
+          break;
+        default:
+          format = GST_FORMAT_BYTES;
+          cur = ttaparse->index[ttaparse->current_frame].pos;
+          end = ttaparse->index[ttaparse->num_frames].pos +
+              ttaparse->index[ttaparse->num_frames].size;
+          break;
       }
+      gst_query_set_position (query, format, cur, end);
       break;
     }
     default:
-      gst_pad_event_default (pad, event);
+      return FALSE;
       break;
   }
+  return TRUE;
 }
 
-static void
-gst_tta_parse_chain (GstPad * pad, GstData * in)
+static gboolean
+gst_tta_parse_activate (GstPad * pad)
+{
+  if (gst_pad_check_pull_range (pad)) {
+    return gst_pad_activate_pull (pad, TRUE);
+  }
+  return FALSE;
+}
+
+static gboolean
+gst_tta_parse_activate_pull (GstPad * pad, gboolean active)
 {
-  GstTtaParse *ttaparse;
-  GstBuffer *outbuf, *buf = GST_BUFFER (in);
+  GstTtaParse *ttaparse = GST_TTA_PARSE (GST_OBJECT_PARENT (pad));
+
+  if (active) {
+    gst_pad_start_task (pad, (GstTaskFunction) gst_tta_parse_loop, ttaparse);
+  } else {
+    gst_pad_stop_task (pad);
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_tta_parse_parse_header (GstTtaParse * ttaparse)
+{
+  GstFlowReturn res;
   guchar *data;
-  gint i;
-  guint64 size, offset = 0;
+  GstBuffer *buf = NULL;
+  guint32 crc;
+  double frame_length;
+  int num_frames;
   GstCaps *caps;
+  int i;
+  guint32 offset;
+  GstEvent *discont;
+
+  if ((res = gst_pad_pull_range (ttaparse->sinkpad,
+              0, 22, &buf)) != GST_FLOW_OK)
+    goto pull_fail;
+  data = GST_BUFFER_DATA (buf);
+  ttaparse->channels = GST_READ_UINT16_LE (data + 6);
+  ttaparse->bits = GST_READ_UINT16_LE (data + 8);
+  ttaparse->samplerate = GST_READ_UINT32_LE (data + 10);
+  ttaparse->data_length = GST_READ_UINT32_LE (data + 14);
+  crc = crc32 (data, 18);
+  if (crc != GST_READ_UINT32_LE (data + 18)) {
+    GST_DEBUG ("Header CRC wrong!");
+  }
+  frame_length = FRAME_TIME * ttaparse->samplerate;
+  num_frames = (ttaparse->data_length / frame_length) + 1;
+  ttaparse->num_frames = num_frames;
+  gst_buffer_unref (buf);
+
+  ttaparse->index =
+      (GstTtaIndex *) g_malloc (num_frames * sizeof (GstTtaIndex));
+  if ((res = gst_pad_pull_range (ttaparse->sinkpad,
+              22, num_frames * 4 + 4, &buf)) != GST_FLOW_OK)
+    goto pull_fail;
+  data = GST_BUFFER_DATA (buf);
+
+  offset = 22 + num_frames * 4 + 4;     // header size + seektable size
+  for (i = 0; i < num_frames; i++) {
+    ttaparse->index[i].size = GST_READ_UINT32_LE (data + i * 4);
+    ttaparse->index[i].pos = offset;
+    offset += ttaparse->index[i].size;
+    ttaparse->index[i].time = i * FRAME_TIME * GST_SECOND;
+  }
+  crc = crc32 (data, num_frames * 4);
+  if (crc != GST_READ_UINT32_LE (data + num_frames * 4)) {
+    GST_DEBUG ("Seektable CRC wrong!");
+  }
 
-  g_return_if_fail (GST_IS_PAD (pad));
-  g_return_if_fail (buf != NULL);
+  GST_DEBUG
+      ("channels: %u, bits: %u, samplerate: %u, data_length: %u, num_frames: %u",
+      ttaparse->channels, ttaparse->bits, ttaparse->samplerate,
+      ttaparse->data_length, num_frames);
 
-  ttaparse = GST_TTA_PARSE (GST_OBJECT_PARENT (pad));
-  g_return_if_fail (GST_IS_TTA_PARSE (ttaparse));
+  ttaparse->header_parsed = TRUE;
+  caps = gst_caps_new_simple ("audio/x-tta",
+      "width", G_TYPE_INT, ttaparse->bits,
+      "channels", G_TYPE_INT, ttaparse->channels,
+      "rate", G_TYPE_INT, ttaparse->samplerate, NULL);
+  gst_pad_set_caps (ttaparse->srcpad, caps);
 
-  if (GST_IS_EVENT (buf)) {
-    gst_tta_handle_event (pad, buf);
-    return;
-  }
+  discont =
+      gst_event_new_newsegment (1.0, GST_FORMAT_TIME, 0,
+      num_frames * FRAME_TIME * GST_SECOND, 0);
 
-  if (ttaparse->partialbuf) {
-    GstBuffer *newbuf;
+  gst_pad_push_event (ttaparse->srcpad, discont);
 
-    newbuf = gst_buffer_merge (ttaparse->partialbuf, buf);
-    gst_buffer_unref (buf);
-    gst_buffer_unref (ttaparse->partialbuf);
-    ttaparse->partialbuf = newbuf;
-  } else {
-    ttaparse->partialbuf = buf;
+  return GST_FLOW_OK;
+
+pull_fail:
+  {
+    GST_ELEMENT_ERROR (ttaparse, STREAM, DEMUX, (NULL),
+        ("Couldn't read header"));
+    return GST_FLOW_ERROR;
   }
+}
 
-  size = GST_BUFFER_SIZE (ttaparse->partialbuf);
-  data = GST_BUFFER_DATA (ttaparse->partialbuf);
-  if (!ttaparse->header_parsed) {
-    if ((*data == 'T') && (*(data + 1) == 'T') && (*(data + 2) == 'A')) {
-      double frame_length;
-      int num_frames;
-      guint32 datasize = 0;
-      guint32 crc;
-
-      offset = offset + 4;
-      offset = offset + 2;
-      ttaparse->channels = GST_READ_UINT16_LE (data + offset);
-      offset = offset + 2;
-      ttaparse->bits = GST_READ_UINT16_LE (data + offset);
-      offset += 2;
-      ttaparse->samplerate = GST_READ_UINT32_LE (data + offset);
-      frame_length = FRAME_TIME * ttaparse->samplerate;
-      offset += 4;
-      ttaparse->data_length = GST_READ_UINT32_LE (data + offset);
-      offset += 4;
-      num_frames = (ttaparse->data_length / frame_length) + 1;
-      crc = crc32 (data, 18);
-      if (crc != GST_READ_UINT32_LE (data + offset)) {
-        GST_WARNING_OBJECT (ttaparse, "Header CRC wrong!");
-      }
-      offset += 4;
-      GST_INFO_OBJECT (ttaparse,
-          "channels: %u, bits: %u, samplerate: %u, data_length: %u, num_frames: %u",
-          ttaparse->channels, ttaparse->bits, ttaparse->samplerate,
-          ttaparse->data_length, num_frames);
-      ttaparse->index =
-          (GstTtaIndex *) g_malloc (num_frames * sizeof (GstTtaIndex));
-      ttaparse->num_frames = num_frames;
-      for (i = 0; i < num_frames; i++) {
-        ttaparse->index[i].size = GST_READ_UINT32_LE (data + offset);
-        ttaparse->index[i].pos = GST_BUFFER_OFFSET (ttaparse->partialbuf) + (num_frames) * 4 + 4 + datasize + 22;       // 22 == header size, +4 for the TTA1
-        ttaparse->index[i].time = i * FRAME_TIME * 1000000000;
-        offset += 4;
-        datasize += ttaparse->index[i].size;
-      }
-      GST_DEBUG_OBJECT (ttaparse, "Datasize: %u", datasize);
-      crc = crc32 (data + 22, num_frames * 4);
-      if (crc != GST_READ_UINT32_LE (data + offset)) {
-        GST_WARNING_OBJECT (ttaparse, "Seek table CRC wrong!");
-      } else {
-        ttaparse->seek_ok = TRUE;
-        /*
-           g_print("allowing seeking!\n");
-           g_print("dumping index:\n");
-           for (i = 0; i < ttaparse->num_frames; i++) {
-           g_print("frame %u: offset = %llu, time=%llu, size=%u\n",
-           i,
-           ttaparse->index[i].pos,
-           ttaparse->index[i].time,
-           ttaparse->index[i].size);
-           }
-         */
-      }
-      offset += 4;
-      ttaparse->header_parsed = TRUE;
-      caps = gst_caps_new_simple ("audio/x-tta",
-          "width", G_TYPE_INT, ttaparse->bits,
-          "channels", G_TYPE_INT, ttaparse->channels,
-          "rate", G_TYPE_INT, ttaparse->samplerate, NULL);
-      gst_pad_set_explicit_caps (ttaparse->srcpad, caps);
-    }
+static GstFlowReturn
+gst_tta_parse_stream_data (GstTtaParse * ttaparse)
+{
+  GstBuffer *buf = NULL;
+  GstFlowReturn res = GST_FLOW_OK;
+
+  if (ttaparse->current_frame >= ttaparse->num_frames)
+    goto found_eos;
+
+  GST_DEBUG ("playing frame %u of %u", ttaparse->current_frame + 1,
+      ttaparse->num_frames);
+  if ((res = gst_pad_pull_range (ttaparse->sinkpad,
+              ttaparse->index[ttaparse->current_frame].pos,
+              ttaparse->index[ttaparse->current_frame].size,
+              &buf)) != GST_FLOW_OK)
+    goto pull_error;
+
+  GST_BUFFER_OFFSET (buf) = ttaparse->index[ttaparse->current_frame].pos;
+  GST_BUFFER_TIMESTAMP (buf) = ttaparse->index[ttaparse->current_frame].time;
+  if (ttaparse->current_frame + 1 == ttaparse->num_frames) {
+    guint32 samples =
+        ttaparse->data_length % (gint64) (ttaparse->samplerate * FRAME_TIME);
+    gdouble frametime = (gdouble) samples / (gdouble) ttaparse->samplerate;
+
+    GST_BUFFER_DURATION (buf) = (guint64) (frametime * GST_SECOND);
+  } else {
+    GST_BUFFER_DURATION (buf) = FRAME_TIME * GST_SECOND;
   }
+  gst_buffer_set_caps (buf, GST_PAD_CAPS (ttaparse->srcpad));
 
-  i = ttaparse->current_frame;
-  while (size - offset >= ttaparse->index[i].size) {
-    guint32 crc;
+  if ((res = gst_pad_push (ttaparse->srcpad, buf)) != GST_FLOW_OK)
+    goto push_error;
+  ttaparse->current_frame++;
 
-    crc = crc32 (data + offset, ttaparse->index[i].size - 4);
-    if (crc != GST_READ_UINT32_LE (data + offset + ttaparse->index[i].size - 4)) {
-      GST_WARNING_OBJECT (ttaparse, "Frame %u corrupted :(", i);
-      GST_WARNING_OBJECT (ttaparse, "calculated crc: %u, got crc: %u", crc,
-          GST_READ_UINT32_LE (data + offset + ttaparse->index[i].size - 4));
-    }
-    outbuf =
-        gst_buffer_create_sub (ttaparse->partialbuf, offset,
-        ttaparse->index[i].size - 4);
-    GST_BUFFER_TIMESTAMP (outbuf) = ttaparse->index[i].time;
-    if (ttaparse->current_frame + 1 == ttaparse->num_frames) {
-      guint32 samples =
-          ttaparse->data_length % (gint64) (ttaparse->samplerate * FRAME_TIME);
-      gdouble frametime = (gdouble) samples / (gdouble) ttaparse->samplerate;
-
-      GST_BUFFER_DURATION (outbuf) = (guint64) (frametime * GST_SECOND);
-    } else {
-      GST_BUFFER_DURATION (outbuf) = FRAME_TIME * 1000000000;
-    }
-    gst_pad_push (ttaparse->srcpad, GST_DATA (outbuf));
-    offset += ttaparse->index[i].size;
-    ttaparse->current_frame++;
-    i = ttaparse->current_frame;
+  return res;
+
+found_eos:
+  {
+    GST_DEBUG ("found EOS");
+    gst_pad_push_event (ttaparse->srcpad, gst_event_new_eos ());
+    return GST_FLOW_WRONG_STATE;
   }
+pull_error:
+  {
+    GST_DEBUG ("Error getting frame from the sinkpad");
+    return res;
+  }
+push_error:
+  {
+    GST_DEBUG ("Error pushing on srcpad");
+    return res;
+  }
+}
+
+static void
+gst_tta_parse_loop (GstTtaParse * ttaparse)
+{
+  GstFlowReturn ret;
+
+  if (!ttaparse->header_parsed)
+    if ((ret = gst_tta_parse_parse_header (ttaparse)) != GST_FLOW_OK)
+      goto pause;
+  if ((ret = gst_tta_parse_stream_data (ttaparse)) != GST_FLOW_OK)
+    goto pause;
+
+  return;
+
+pause:
+  GST_LOG_OBJECT (ttaparse, "pausing task %d", ret);
+  gst_pad_pause_task (ttaparse->sinkpad);
+  if (GST_FLOW_IS_FATAL (ret)) {
+    GST_ELEMENT_ERROR (ttaparse, STREAM, STOPPED,
+        ("streaming stopped, reason %d", ret),
+        ("streaming stopped, reason %d", ret));
+    gst_pad_push_event (ttaparse->srcpad, gst_event_new_eos ());
+  }
+}
+
+static GstStateChangeReturn
+gst_tta_parse_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstTtaParse *ttaparse = GST_TTA_PARSE (element);
 
-  if (size - offset > 0) {
-    glong remainder = size - offset;
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
-    outbuf = gst_buffer_create_sub (ttaparse->partialbuf, offset, remainder);
-    gst_buffer_unref (ttaparse->partialbuf);
-    ttaparse->partialbuf = outbuf;
-  } else {
-    gst_buffer_unref (ttaparse->partialbuf);
-    ttaparse->partialbuf = NULL;
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_tta_parse_reset (ttaparse);
+      break;
+    default:
+      break;
   }
 
+  return ret;
 }
 
 gboolean
index 10ea31a..a287d6d 100644 (file)
@@ -42,7 +42,6 @@ typedef struct _GstTtaParse      GstTtaParse;
 typedef struct _GstTtaParseClass GstTtaParseClass;
 
 typedef struct _GstTtaIndex {
-  guint32   frameno;
   guint32   size;     /* size of frame frameno */
   guint64   pos;      /* start of the frame */
   guint64   time;     /* in nanoseconds */
@@ -54,16 +53,14 @@ struct _GstTtaParse
 
   GstPad *sinkpad, *srcpad;
 
-  gboolean silent;
   gboolean header_parsed;
-  GstBuffer *partialbuf;
   guint32 samplerate;
   guint16 channels;
   guint16 bits;
   guint32 data_length;
-  GstTtaIndex *index;
   guint num_frames;
-  gboolean seek_ok;
+
+  GstTtaIndex *index;
 
   guint32 current_frame;
 };