Port flacdec (seeking is still slow'ish).
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>
Mon, 22 Aug 2005 11:20:18 +0000 (11:20 +0000)
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>
Mon, 22 Aug 2005 11:20:18 +0000 (11:20 +0000)
Original commit message from CVS:
* configure.ac:
* ext/Makefile.am:
* ext/flac/Makefile.am:
* ext/flac/gstflac.c: (plugin_init):
* ext/flac/gstflacdec.c: (flacdec_get_type), (gst_flacdec_init),
(gst_flacdec_update_metadata), (gst_flacdec_seek),
(gst_flacdec_tell), (gst_flacdec_length), (gst_flacdec_read),
(gst_flacdec_write), (gst_flacdec_loop),
(gst_flacdec_get_src_query_types), (gst_flacdec_src_query),
(gst_flacdec_src_event), (gst_flacdec_sink_activate),
(gst_flacdec_sink_activate_pull), (gst_flacdec_change_state):
* ext/flac/gstflacdec.h:
Port flacdec (seeking is still slow'ish).

ChangeLog
configure.ac
ext/Makefile.am
ext/flac/Makefile.am
ext/flac/gstflac.c
ext/flac/gstflacdec.c
ext/flac/gstflacdec.h

index 9462e57..c77cc7c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2005-08-22  Ronald S. Bultje  <rbultje@ronald.bitfreak.net>
+
+       * configure.ac:
+       * ext/Makefile.am:
+       * ext/flac/Makefile.am:
+       * ext/flac/gstflac.c: (plugin_init):
+       * ext/flac/gstflacdec.c: (flacdec_get_type), (gst_flacdec_init),
+       (gst_flacdec_update_metadata), (gst_flacdec_seek),
+       (gst_flacdec_tell), (gst_flacdec_length), (gst_flacdec_read),
+       (gst_flacdec_write), (gst_flacdec_loop),
+       (gst_flacdec_get_src_query_types), (gst_flacdec_src_query),
+       (gst_flacdec_src_event), (gst_flacdec_sink_activate),
+       (gst_flacdec_sink_activate_pull), (gst_flacdec_change_state):
+       * ext/flac/gstflacdec.h:
+         Port flacdec (seeking is still slow'ish).
+
 2005-08-22  Owen Fraser-Green  <owen@discobabe.net>
 
        * gst/realmedia/rmdemux.c: 
index 39efc32..cbf2b27 100644 (file)
@@ -411,6 +411,20 @@ return 0;
   AC_SUBST(FAAD_LIBS)
 ])
 
+dnl *** FLAC ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_FLAC, true)
+GST_CHECK_FEATURE(FLAC, [FLAC lossless audio], flacenc flacdec, [
+  GST_CHECK_LIBHEADER(FLAC, FLAC, FLAC__seekable_stream_encoder_new, -lm, FLAC/all.h, FLAC_LIBS="-lFLAC -lm")
+  dnl API change in FLAC 1.1.1, so require that...
+  if test x$HAVE_FLAC = xyes; then
+    AC_CHECK_DECL(FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR,
+                  HAVE_FLAC="yes", HAVE_FLAC="no", [
+#include <FLAC/seekable_stream_encoder.h>
+                  ])
+  fi
+  AC_SUBST(FLAC_LIBS)
+])
+
 dnl *** lame ***
 translit(dnm, m, l) AM_CONDITIONAL(USE_LAME, true)
 GST_CHECK_FEATURE(LAME, [lame mp3 encoder library], lame, [
@@ -653,6 +667,7 @@ sys/oss/Makefile
 ext/Makefile
 ext/aalib/Makefile
 ext/dv/Makefile
+ext/flac/Makefile
 ext/gconf/Makefile
 ext/lame/Makefile
 ext/libcaca/Makefile
index 4fb0317..7f1ea76 100644 (file)
@@ -118,11 +118,11 @@ endif
 ## FESTIVAL_DIR=
 ## endif
 
-if USE_FLAC
-FLAC_DIR=flac
-else
+if USE_FLAC
+FLAC_DIR=flac
+else
 FLAC_DIR=
-endif
+endif
 
 if USE_GCONF
 GCONF_DIR=gconf
@@ -451,6 +451,7 @@ DIST_SUBDIRS=\
        dv \
        amrnb \
        faad \
+       flac \
        mpeg2dec \
        jpeg \
        libpng \
index be66e70..191e2ee 100644 (file)
@@ -1,7 +1,8 @@
 
 plugin_LTLIBRARIES = libgstflac.la
 
-libgstflac_la_SOURCES = gstflac.c gstflacenc.c gstflacdec.c gstflactag.c
+libgstflac_la_SOURCES = gstflac.c gstflacdec.c
+#gstflacenc.c gstflactag.c
 libgstflac_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)
 libgstflac_la_LIBADD = $(FLAC_LIBS) 
 libgstflac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
index 9432713..28aa4e1 100644 (file)
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  if (!gst_library_load ("gstbytestream"))
-    return FALSE;
-
-  /* we need the gsttags plugin for metadata querying */
-  if (!gst_plugin_load ("gsttags"))
-    return FALSE;
-
+#if 0
   if (!gst_element_register (plugin, "flacenc", GST_RANK_NONE,
           GST_TYPE_FLACENC))
     return FALSE;
-
+#endif
   if (!gst_element_register (plugin, "flacdec", GST_RANK_PRIMARY,
           GST_TYPE_FLACDEC))
     return FALSE;
-
+#if 0
   if (!gst_element_register (plugin, "flactag", GST_RANK_PRIMARY,
           gst_flac_tag_get_type ()))
     return FALSE;
-
+#endif
   return TRUE;
 }
 
index 480b803..8289bf4 100644 (file)
 #endif
 #include <string.h>
 
-/*#define DEBUG_ENABLED */
 #include "gstflacdec.h"
 #include <gst/gsttaginterface.h>
 
-#include <gst/tag/tag.h>
+//#include <gst/tag/tag.h>
 
 #include "flac_compat.h"
 
+GST_DEBUG_CATEGORY_STATIC (flacdec_debug);
+#define GST_CAT_DEFAULT flacdec_debug
+
 static GstPadTemplate *src_template, *sink_template;
 
 /* elementfactory information */
@@ -40,34 +42,21 @@ GstElementDetails flacdec_details = {
   "Wim Taymans <wim.taymans@chello.be>",
 };
 
-/* FlacDec signals and args */
-enum
-{
-  /* FILL ME */
-  LAST_SIGNAL
-};
-
-enum
-{
-  ARG_0,
-  ARG_METADATA
-};
-
 static void gst_flacdec_base_init (gpointer g_class);
 static void gst_flacdec_class_init (FlacDecClass * klass);
 static void gst_flacdec_init (FlacDec * flacdec);
 static void gst_flacdec_finalize (GObject * object);
 
-static void gst_flacdec_loop (GstElement * element);
+static void gst_flacdec_loop (GstPad * pad);
 static GstElementStateReturn gst_flacdec_change_state (GstElement * element);
-static const GstFormat *gst_flacdec_get_src_formats (GstPad * pad);
+static const GstQueryType *gst_flacdec_get_src_query_types (GstPad * pad);
+static gboolean gst_flacdec_src_query (GstPad * pad, GstQuery * query);
 static gboolean gst_flacdec_convert_src (GstPad * pad, GstFormat src_format,
     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
-static const GstQueryType *gst_flacdec_get_src_query_types (GstPad * pad);
-static gboolean gst_flacdec_src_query (GstPad * pad, GstQueryType type,
-    GstFormat * format, gint64 * value);
-static const GstEventMask *gst_flacdec_get_src_event_masks (GstPad * pad);
 static gboolean gst_flacdec_src_event (GstPad * pad, GstEvent * event);
+static gboolean gst_flacdec_sink_activate (GstPad * sinkpad);
+static gboolean gst_flacdec_sink_activate_pull (GstPad * sinkpad,
+    gboolean active);
 
 static FLAC__SeekableStreamDecoderReadStatus
 gst_flacdec_read (const FLAC__SeekableStreamDecoder * decoder,
@@ -116,6 +105,8 @@ flacdec_get_type (void)
 
     flacdec_type =
         g_type_register_static (GST_TYPE_ELEMENT, "FlacDec", &flacdec_info, 0);
+
+    GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder");
   }
   return flacdec_type;
 }
@@ -178,21 +169,18 @@ static void
 gst_flacdec_init (FlacDec * flacdec)
 {
   flacdec->sinkpad = gst_pad_new_from_template (sink_template, "sink");
+  gst_pad_set_activate_function (flacdec->sinkpad, gst_flacdec_sink_activate);
+  gst_pad_set_activatepull_function (flacdec->sinkpad,
+      gst_flacdec_sink_activate_pull);
   gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->sinkpad);
-  gst_pad_set_convert_function (flacdec->sinkpad, NULL);
 
-  gst_element_set_loop_function (GST_ELEMENT (flacdec), gst_flacdec_loop);
   flacdec->srcpad = gst_pad_new_from_template (src_template, "src");
-  gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->srcpad);
-  gst_pad_set_formats_function (flacdec->srcpad, gst_flacdec_get_src_formats);
-  gst_pad_set_convert_function (flacdec->srcpad, gst_flacdec_convert_src);
   gst_pad_set_query_type_function (flacdec->srcpad,
       gst_flacdec_get_src_query_types);
   gst_pad_set_query_function (flacdec->srcpad, gst_flacdec_src_query);
-  gst_pad_set_event_mask_function (flacdec->srcpad,
-      gst_flacdec_get_src_event_masks);
   gst_pad_set_event_function (flacdec->srcpad, gst_flacdec_src_event);
-  gst_pad_use_explicit_caps (flacdec->srcpad);
+  gst_pad_use_fixed_caps (flacdec->srcpad);
+  gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->srcpad);
 
   flacdec->decoder = FLAC__seekable_stream_decoder_new ();
   flacdec->total_samples = 0;
@@ -262,7 +250,7 @@ gst_flacdec_update_metadata (FlacDec * flacdec,
   value = NULL;
   GST_DEBUG ("%d tag(s) found", number_of_comments);
   for (cursor = 0; cursor < number_of_comments; cursor++) {
-    str_ptr = metadata->data.vorbis_comment.comments[cursor].entry;
+    str_ptr = (gchar *) metadata->data.vorbis_comment.comments[cursor].entry;
     str_len = metadata->data.vorbis_comment.comments[cursor].length;
     p_value = g_strstr_len (str_ptr, str_len, "=");
     if (p_value) {
@@ -270,7 +258,7 @@ gst_flacdec_update_metadata (FlacDec * flacdec,
       value = g_strndup (p_value + 1, str_ptr + str_len - p_value - 1);
 
       GST_DEBUG ("%s : %s", name, value);
-      gst_vorbis_tag_add (list, name, value);
+      //gst_vorbis_tag_add (list, name, value);
       g_free (name);
       g_free (value);
     }
@@ -278,10 +266,8 @@ gst_flacdec_update_metadata (FlacDec * flacdec,
   gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       GST_TAG_AUDIO_CODEC, "FLAC", NULL);
 
-  gst_element_found_tags (GST_ELEMENT (flacdec), list);
-  if (GST_PAD_IS_USABLE (flacdec->srcpad)) {
-    gst_pad_push (flacdec->srcpad, GST_DATA (gst_event_new_tag (list)));
-  }
+  gst_element_found_tags_for_pad (GST_ELEMENT (flacdec), flacdec->srcpad, list);
+
   return TRUE;
 }
 
@@ -342,9 +328,8 @@ gst_flacdec_seek (const FLAC__SeekableStreamDecoder * decoder,
   flacdec = GST_FLACDEC (client_data);
 
   GST_DEBUG ("seek %" G_GINT64_FORMAT, position);
-  if (!gst_bytestream_seek (flacdec->bs, position, GST_SEEK_METHOD_SET)) {
-    return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
-  }
+  flacdec->offset = position;
+
   return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
 }
 
@@ -356,9 +341,7 @@ gst_flacdec_tell (const FLAC__SeekableStreamDecoder * decoder,
 
   flacdec = GST_FLACDEC (client_data);
 
-  *position = gst_bytestream_tell (flacdec->bs);
-  if (*position == -1)
-    return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+  *position = flacdec->offset;
 
   GST_DEBUG ("tell %" G_GINT64_FORMAT, *position);
 
@@ -370,12 +353,20 @@ gst_flacdec_length (const FLAC__SeekableStreamDecoder * decoder,
     FLAC__uint64 * length, void *client_data)
 {
   FlacDec *flacdec;
+  GstFormat fmt = GST_FORMAT_BYTES;
+  gint64 len;
+  GstPad *peer;
 
   flacdec = GST_FLACDEC (client_data);
 
-  *length = gst_bytestream_length (flacdec->bs);
-  if (*length == -1)
+  if (!(peer = gst_pad_get_peer (flacdec->sinkpad)))
     return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+  gst_pad_query_position (peer, &fmt, NULL, &len);
+  gst_object_unref (peer);
+  if (fmt != GST_FORMAT_BYTES || len == -1)
+    return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+
+  *length = len;
 
   GST_DEBUG ("length %" G_GINT64_FORMAT, *length);
 
@@ -398,51 +389,20 @@ gst_flacdec_read (const FLAC__SeekableStreamDecoder * decoder,
     FLAC__byte buffer[], unsigned *bytes, void *client_data)
 {
   FlacDec *flacdec;
-  gint insize = 0;
-  guint8 *indata;
+  GstBuffer *buf;
 
   flacdec = GST_FLACDEC (client_data);
 
-  //g_print ("read %u\n", *bytes);
+  if (gst_pad_pull_range (flacdec->sinkpad, flacdec->offset, *bytes,
+          &buf) != GST_FLOW_OK)
+    return FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR;
 
-  while (insize == 0) {
-    insize = gst_bytestream_peek_bytes (flacdec->bs, &indata, *bytes);
-    if (insize < *bytes) {
-      GstEvent *event;
-      guint32 avail;
-
-      gst_bytestream_get_status (flacdec->bs, &avail, &event);
-
-      switch (GST_EVENT_TYPE (event)) {
-        case GST_EVENT_EOS:
-          GST_DEBUG ("eos");
-          flacdec->eos = TRUE;
-          gst_event_unref (event);
-          if (avail == 0) {
-            return 0;
-          }
-          break;
-        case GST_EVENT_DISCONTINUOUS:
-          GST_DEBUG ("discont");
-
-          /* we are not yet sending the discont, we'll do that in the next write operation */
-          flacdec->need_discont = TRUE;
-          gst_event_unref (event);
-          break;
-        default:
-          gst_pad_event_default (flacdec->sinkpad, event);
-          break;
-      }
-      if (avail > 0)
-        insize = gst_bytestream_peek_bytes (flacdec->bs, &indata, avail);
-      else
-        insize = 0;
-    }
-  }
-
-  memcpy (buffer, indata, insize);
-  *bytes = insize;
-  gst_bytestream_flush_fast (flacdec->bs, insize);
+  GST_DEBUG ("Read %d bytes at %" G_GUINT64_FORMAT,
+      GST_BUFFER_SIZE (buf), flacdec->offset);
+  memcpy (buffer, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+  *bytes = GST_BUFFER_SIZE (buf);
+  gst_buffer_unref (buf);
+  flacdec->offset += *bytes;
 
   return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
 }
@@ -458,6 +418,7 @@ gst_flacdec_write (const FLAC__SeekableStreamDecoder * decoder,
   guint channels = frame->header.channels;
   guint samples = frame->header.blocksize;
   guint j, i;
+  GstFlowReturn ret;
 
   flacdec = GST_FLACDEC (client_data);
 
@@ -472,68 +433,73 @@ gst_flacdec_write (const FLAC__SeekableStreamDecoder * decoder,
       flacdec->total_samples = flacdec->seek_value;
     }
 
-    if (GST_PAD_IS_USABLE (flacdec->srcpad)) {
-      GST_DEBUG ("send discont");
+    GST_DEBUG ("send discont to %" G_GUINT64_FORMAT, flacdec->seek_value);
 
-      format = GST_FORMAT_TIME;
-      gst_pad_convert (flacdec->srcpad, GST_FORMAT_DEFAULT,
-          flacdec->total_samples, &format, &time);
-      format = GST_FORMAT_BYTES;
-      gst_pad_convert (flacdec->srcpad, GST_FORMAT_DEFAULT,
-          flacdec->total_samples, &format, &bytes);
-      discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time,
-          GST_FORMAT_BYTES, bytes,
-          GST_FORMAT_DEFAULT, flacdec->total_samples, NULL);
+    format = GST_FORMAT_TIME;
+    gst_flacdec_convert_src (flacdec->srcpad, GST_FORMAT_DEFAULT,
+        flacdec->total_samples, &format, &time);
+    format = GST_FORMAT_BYTES;
+    gst_flacdec_convert_src (flacdec->srcpad, GST_FORMAT_DEFAULT,
+        flacdec->total_samples, &format, &bytes);
+    discont = gst_event_new_newsegment (1.0, GST_FORMAT_TIME, time,
+        GST_CLOCK_TIME_NONE, 0);
 
-      gst_pad_push (flacdec->srcpad, GST_DATA (discont));
-    }
+    if (!gst_pad_push_event (flacdec->srcpad, discont))
+      return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   }
 
   if (!GST_PAD_CAPS (flacdec->srcpad)) {
-    gst_pad_set_explicit_caps (flacdec->srcpad,
-        gst_caps_new_simple ("audio/x-raw-int",
-            "endianness", G_TYPE_INT, G_BYTE_ORDER,
-            "signed", G_TYPE_BOOLEAN, TRUE,
-            "width", G_TYPE_INT, depth,
-            "depth", G_TYPE_INT, depth,
-            "rate", G_TYPE_INT, frame->header.sample_rate,
-            "channels", G_TYPE_INT, channels, NULL));
+    GST_DEBUG ("Negotiating %d Hz @ %d channels",
+        frame->header.sample_rate, channels);
+
+    if (!gst_pad_set_caps (flacdec->srcpad,
+            gst_caps_new_simple ("audio/x-raw-int",
+                "endianness", G_TYPE_INT, G_BYTE_ORDER,
+                "signed", G_TYPE_BOOLEAN, TRUE,
+                "width", G_TYPE_INT, depth,
+                "depth", G_TYPE_INT, depth,
+                "rate", G_TYPE_INT, frame->header.sample_rate,
+                "channels", G_TYPE_INT, channels, NULL)))
+      return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 
     flacdec->depth = depth;
     flacdec->channels = channels;
     flacdec->frequency = frame->header.sample_rate;
   }
 
-  if (GST_PAD_IS_USABLE (flacdec->srcpad)) {
-    outbuf = gst_buffer_new ();
-    GST_BUFFER_SIZE (outbuf) = samples * channels * ((depth + 7) >> 3);
-    GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
-    GST_BUFFER_TIMESTAMP (outbuf) =
-        flacdec->total_samples * GST_SECOND / frame->header.sample_rate;
-    GST_BUFFER_DURATION (outbuf) =
-        samples * GST_SECOND / frame->header.sample_rate;
-
-    if (depth == 8) {
-      guint8 *outbuffer = (guint8 *) GST_BUFFER_DATA (outbuf);
-
-      for (i = 0; i < samples; i++) {
-        for (j = 0; j < channels; j++) {
-          *outbuffer++ = (guint8) buffer[j][i];
-        }
+  gst_pad_alloc_buffer (flacdec->srcpad, flacdec->total_samples,
+      samples * channels * ((depth + 7) >> 3), GST_PAD_CAPS (flacdec->srcpad),
+      &outbuf);
+  GST_BUFFER_TIMESTAMP (outbuf) =
+      flacdec->total_samples * GST_SECOND / frame->header.sample_rate;
+  GST_BUFFER_DURATION (outbuf) =
+      samples * GST_SECOND / frame->header.sample_rate;
+
+  if (depth == 8) {
+    guint8 *outbuffer = (guint8 *) GST_BUFFER_DATA (outbuf);
+
+    for (i = 0; i < samples; i++) {
+      for (j = 0; j < channels; j++) {
+        *outbuffer++ = (guint8) buffer[j][i];
       }
-    } else if (depth == 16) {
-      guint16 *outbuffer = (guint16 *) GST_BUFFER_DATA (outbuf);
+    }
+  } else if (depth == 16) {
+    guint16 *outbuffer = (guint16 *) GST_BUFFER_DATA (outbuf);
 
-      for (i = 0; i < samples; i++) {
-        for (j = 0; j < channels; j++) {
-          *outbuffer++ = (guint16) buffer[j][i];
-        }
+    for (i = 0; i < samples; i++) {
+      for (j = 0; j < channels; j++) {
+        *outbuffer++ = (guint16) buffer[j][i];
       }
-    } else {
-      g_warning ("flacdec: invalid depth %d found\n", depth);
-      return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
     }
-    gst_pad_push (flacdec->srcpad, GST_DATA (outbuf));
+  } else {
+    g_warning ("flacdec: invalid depth %d found\n", depth);
+    return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+  }
+  GST_DEBUG ("Writing %d samples", samples);
+  ret = gst_pad_push (flacdec->srcpad, outbuf);
+  if (ret != GST_FLOW_NOT_LINKED && ret != GST_FLOW_OK) {
+    GST_DEBUG ("Invalid return code");
+    return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
   }
   flacdec->total_samples += samples;
 
@@ -541,12 +507,15 @@ gst_flacdec_write (const FLAC__SeekableStreamDecoder * decoder,
 }
 
 static void
-gst_flacdec_loop (GstElement * element)
+gst_flacdec_loop (GstPad * sinkpad)
 {
   FlacDec *flacdec;
   gboolean res;
+  FLAC__SeekableStreamDecoderState s;
 
-  flacdec = GST_FLACDEC (element);
+  flacdec = GST_FLACDEC (GST_OBJECT_PARENT (sinkpad));
+
+  GST_STREAM_LOCK (sinkpad);
 
   GST_DEBUG ("flacdec: entering loop");
   if (flacdec->init) {
@@ -557,7 +526,7 @@ gst_flacdec_loop (GstElement * element)
     if (res != FLAC__SEEKABLE_STREAM_DECODER_OK) {
       GST_ELEMENT_ERROR (flacdec, LIBRARY, INIT, (NULL),
           (FLAC__SeekableStreamDecoderStateString[res]));
-      return;
+      goto end;
     }
     /*    FLAC__seekable_stream_decoder_process_metadata (flacdec->decoder); */
     flacdec->init = FALSE;
@@ -569,6 +538,7 @@ gst_flacdec_loop (GstElement * element)
     if (FLAC__seekable_stream_decoder_seek_absolute (flacdec->decoder,
             flacdec->seek_value)) {
       flacdec->total_samples = flacdec->seek_value;
+      flacdec->need_discont = TRUE;
       GST_DEBUG ("seek done");
     } else {
       GST_DEBUG ("seek failed");
@@ -578,24 +548,35 @@ gst_flacdec_loop (GstElement * element)
 
   GST_DEBUG ("flacdec: processing single");
   res = FLAC__seekable_stream_decoder_process_single (flacdec->decoder);
+  if (!res)
+    goto end;
   GST_DEBUG ("flacdec: checking for EOS");
-  if (FLAC__seekable_stream_decoder_get_state (flacdec->decoder) ==
+  if ((s = FLAC__seekable_stream_decoder_get_state (flacdec->decoder)) ==
       FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) {
     GstEvent *event;
 
     GST_DEBUG ("flacdec: sending EOS event");
     FLAC__seekable_stream_decoder_reset (flacdec->decoder);
 
-    if (GST_PAD_IS_USABLE (flacdec->srcpad)) {
-      event = gst_event_new (GST_EVENT_EOS);
-      gst_pad_push (flacdec->srcpad, GST_DATA (event));
-    }
-    gst_element_set_eos (element);
+    event = gst_event_new_eos ();
+    if (!gst_pad_push_event (flacdec->srcpad, event))
+      goto end;
+  } else if (s >= FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR &&
+      s <= FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK) {
+    GST_DEBUG ("Error: %d", s);
+    goto end;
   }
   GST_DEBUG ("flacdec: _loop end");
-}
+  GST_STREAM_UNLOCK (sinkpad);
+  return;
 
+end:
+  GST_DEBUG ("pausing");
+  gst_pad_pause_task (sinkpad);
+  GST_STREAM_UNLOCK (sinkpad);
+}
 
+#if 0
 static const GstFormat *
 gst_flacdec_get_src_formats (GstPad * pad)
 {
@@ -608,6 +589,7 @@ gst_flacdec_get_src_formats (GstPad * pad)
 
   return formats;
 }
+#endif
 
 static gboolean
 gst_flacdec_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
@@ -676,7 +658,6 @@ static const GstQueryType *
 gst_flacdec_get_src_query_types (GstPad * pad)
 {
   static const GstQueryType types[] = {
-    GST_QUERY_TOTAL,
     GST_QUERY_POSITION,
     0,
   };
@@ -685,30 +666,31 @@ gst_flacdec_get_src_query_types (GstPad * pad)
 }
 
 static gboolean
-gst_flacdec_src_query (GstPad * pad, GstQueryType type,
-    GstFormat * format, gint64 * value)
+gst_flacdec_src_query (GstPad * pad, GstQuery * query)
 {
   gboolean res = TRUE;
   FlacDec *flacdec = GST_FLACDEC (gst_pad_get_parent (pad));
 
-  switch (type) {
-    case GST_QUERY_TOTAL:
-    {
-      guint64 samples;
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_POSITION:{
+      gint64 len, pos;
+      GstFormat fmt = GST_FORMAT_TIME;
 
       if (flacdec->stream_samples == 0)
-        samples = flacdec->total_samples;
+        len = flacdec->total_samples;
       else
-        samples = flacdec->stream_samples;
-
-      res = gst_pad_convert (flacdec->srcpad,
-          GST_FORMAT_DEFAULT, samples, format, value);
+        len = flacdec->stream_samples;
+      pos = flacdec->total_samples;
+
+      if (gst_flacdec_convert_src (flacdec->srcpad,
+              GST_FORMAT_DEFAULT, len, &fmt, &len) &&
+          gst_flacdec_convert_src (flacdec->srcpad,
+              GST_FORMAT_DEFAULT, pos, &fmt, &pos))
+        gst_query_set_position (query, GST_FORMAT_TIME, pos, len);
+      else
+        res = FALSE;
       break;
     }
-    case GST_QUERY_POSITION:
-      res = gst_pad_convert (flacdec->srcpad,
-          GST_FORMAT_DEFAULT, flacdec->total_samples, format, value);
-      break;
     default:
       res = FALSE;
       break;
@@ -717,35 +699,42 @@ gst_flacdec_src_query (GstPad * pad, GstQueryType type,
   return res;
 }
 
-static const GstEventMask *
-gst_flacdec_get_src_event_masks (GstPad * pad)
-{
-  static const GstEventMask masks[] = {
-    {GST_EVENT_SEEK, GST_SEEK_FLAG_ACCURATE},
-    {0, 0},
-  };
-
-  return masks;
-}
-
 static gboolean
 gst_flacdec_src_event (GstPad * pad, GstEvent * event)
 {
   gboolean res = TRUE;
   FlacDec *flacdec = GST_FLACDEC (gst_pad_get_parent (pad));
-  GstFormat format;
 
   switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_SEEK:
+    case GST_EVENT_SEEK:{
+      GstFormat format, seek_fmt;
+      GstSeekType type;
+      gint64 pos;
+
+      gst_event_parse_seek (event, NULL, &seek_fmt, NULL, &type, &pos,
+          NULL, NULL);
+
       format = GST_FORMAT_DEFAULT;
 
-      if (gst_pad_convert (flacdec->srcpad,
-              GST_EVENT_SEEK_FORMAT (event),
-              GST_EVENT_SEEK_OFFSET (event), &format, &flacdec->seek_value))
+      if (type == GST_SEEK_TYPE_SET &&
+          gst_flacdec_convert_src (flacdec->srcpad, seek_fmt, pos,
+              &format, &pos)) {
+        GST_DEBUG ("Initializing seek");
+        g_print ("Grab seek lock\n");
+        gst_pad_push_event (flacdec->srcpad, gst_event_new_flush_start ());
+        GST_STREAM_LOCK (flacdec->sinkpad);
+        g_print ("Got seek lock\n");
+        gst_pad_push_event (flacdec->srcpad, gst_event_new_flush_stop ());
+        GST_DEBUG ("Ready");
         flacdec->seek_pending = TRUE;
-      else
+        flacdec->seek_value = pos;
+        gst_pad_start_task (flacdec->sinkpad,
+            (GstTaskFunction) gst_flacdec_loop, flacdec->sinkpad);
+        GST_STREAM_UNLOCK (flacdec->sinkpad);
+      } else
         res = FALSE;
       break;
+    }
     default:
       res = FALSE;
       break;
@@ -754,30 +743,47 @@ gst_flacdec_src_event (GstPad * pad, GstEvent * event)
   return res;
 }
 
+static gboolean
+gst_flacdec_sink_activate (GstPad * sinkpad)
+{
+  if (gst_pad_check_pull_range (sinkpad))
+    return gst_pad_activate_pull (sinkpad, TRUE);
+
+  return FALSE;
+}
+
+static gboolean
+gst_flacdec_sink_activate_pull (GstPad * sinkpad, gboolean active)
+{
+  if (active) {
+    /* if we have a scheduler we can start the task */
+    GST_FLACDEC (GST_OBJECT_PARENT (sinkpad))->offset = 0;
+    gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flacdec_loop, sinkpad);
+  } else {
+    gst_pad_stop_task (sinkpad);
+  }
+
+  return TRUE;
+}
+
 static GstElementStateReturn
 gst_flacdec_change_state (GstElement * element)
 {
   FlacDec *flacdec = GST_FLACDEC (element);
 
   switch (GST_STATE_TRANSITION (element)) {
-    case GST_STATE_NULL_TO_READY:
     case GST_STATE_READY_TO_PAUSED:
-      flacdec->bs = gst_bytestream_new (flacdec->sinkpad);
       flacdec->seek_pending = FALSE;
       flacdec->total_samples = 0;
       flacdec->eos = FALSE;
+      flacdec->need_discont = TRUE;
       if (flacdec->init == FALSE) {
         FLAC__seekable_stream_decoder_reset (flacdec->decoder);
       }
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
       flacdec->eos = FALSE;
-    case GST_STATE_PLAYING_TO_PAUSED:
-      break;
-    case GST_STATE_PAUSED_TO_READY:
-      gst_bytestream_destroy (flacdec->bs);
       break;
-    case GST_STATE_READY_TO_NULL:
     default:
       break;
   }
index 5b5fd11..04be2e8 100644 (file)
@@ -23,7 +23,6 @@
 
 
 #include <gst/gst.h>
-#include <gst/bytestream/bytestream.h>
 
 #include <FLAC/all.h>
 
@@ -45,7 +44,7 @@ struct _FlacDec {
   GstElement    element;
 
   GstPad       *sinkpad,*srcpad;
-  GstByteStream *bs;
+  guint64       offset;
 
   FLAC__SeekableStreamDecoder *decoder;
   gint          channels;