Index: gstflacdec.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/ext/flac/gstflacdec.c,v
retrieving revision 1.77
diff -u -p -r1.77 gstflacdec.c
--- gstflacdec.c	23 May 2006 16:45:22 -0000	1.77
+++ gstflacdec.c	17 Jun 2006 11:22:28 -0000
@@ -33,14 +33,15 @@
  * gst-launch filesrc location=media/small/dark.441-16-s.flac ! flacdec ! audioconvert ! audioresample ! autoaudiosink
  * </programlisting>
  * </para>
+ * <title>Another example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch gnomevfssrc location=http://gstreamer.freedesktop.org/media/small/dark.441-16-s.flac ! flacdec ! audioconvert ! audioresample ! queue min-threshold-buffers=10 ! autoaudiosink
+ * </programlisting>
+ * </para>
  * </refsect2>
  */
 
-/*
- * FIXME: this pipeline doesn't work, but we want to use it as example
- * gst-launch gnomevfssrc location=http://gstreamer.freedesktop.org/media/small/dark.441-16-s.flac ! flacdec ! autoaudiosink
- */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -60,7 +61,7 @@ static const GstElementDetails flacdec_d
 GST_ELEMENT_DETAILS ("FLAC audio decoder",
     "Codec/Decoder/Audio",
     "Decodes FLAC lossless audio streams",
-    "Wim Taymans <wim.taymans@chello.be>");
+    "Wim Taymans <wim@fluendo.com>");
 
 
 static void gst_flac_dec_finalize (GObject * object);
@@ -69,6 +70,8 @@ static void gst_flac_dec_loop (GstPad * 
 static GstStateChangeReturn gst_flac_dec_change_state (GstElement * element,
     GstStateChange transition);
 static const GstQueryType *gst_flac_dec_get_src_query_types (GstPad * pad);
+static const GstQueryType *gst_flac_dec_get_sink_query_types (GstPad * pad);
+static gboolean gst_flac_dec_sink_query (GstPad * pad, GstQuery * query);
 static gboolean gst_flac_dec_src_query (GstPad * pad, GstQuery * query);
 static gboolean gst_flac_dec_convert_src (GstPad * pad, GstFormat src_format,
     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
@@ -76,11 +79,18 @@ static gboolean gst_flac_dec_src_event (
 static gboolean gst_flac_dec_sink_activate (GstPad * sinkpad);
 static gboolean gst_flac_dec_sink_activate_pull (GstPad * sinkpad,
     gboolean active);
+static gboolean gst_flac_dec_sink_activate_push (GstPad * sinkpad,
+    gboolean active);
 static void gst_flac_dec_send_newsegment (GstFlacDec * flacdec,
     gboolean update);
+static gboolean gst_flac_dec_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_flac_dec_chain (GstPad * pad, GstBuffer * buf);
+static void gst_flac_dec_reset_decoders (GstFlacDec * flacdec);
+static void gst_flac_dec_setup_seekable_decoder (GstFlacDec * flacdec);
+static void gst_flac_dec_setup_stream_decoder (GstFlacDec * flacdec);
 
 static FLAC__SeekableStreamDecoderReadStatus
-gst_flac_dec_read (const FLAC__SeekableStreamDecoder * decoder,
+gst_flac_dec_read_seekable (const FLAC__SeekableStreamDecoder * decoder,
     FLAC__byte buffer[], unsigned *bytes, void *client_data);
 static FLAC__SeekableStreamDecoderSeekStatus
 gst_flac_dec_seek (const FLAC__SeekableStreamDecoder * decoder,
@@ -93,19 +103,32 @@ gst_flac_dec_length (const FLAC__Seekabl
     FLAC__uint64 * length, void *client_data);
 static FLAC__bool gst_flac_dec_eof (const FLAC__SeekableStreamDecoder * decoder,
     void *client_data);
+static FLAC__StreamDecoderReadStatus
+gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
+    FLAC__byte buffer[], unsigned *bytes, void *client_data);
+static FLAC__StreamDecoderWriteStatus
+gst_flac_dec_write_seekable (const FLAC__SeekableStreamDecoder * decoder,
+    const FLAC__Frame * frame,
+    const FLAC__int32 * const buffer[], void *client_data);
 static FLAC__StreamDecoderWriteStatus
-gst_flac_dec_write (const FLAC__SeekableStreamDecoder * decoder,
+gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
     const FLAC__Frame * frame,
     const FLAC__int32 * const buffer[], void *client_data);
-static void gst_flac_dec_metadata_callback (const FLAC__SeekableStreamDecoder *
+static void gst_flac_dec_metadata_callback_seekable (const FLAC__SeekableStreamDecoder *
     decoder, const FLAC__StreamMetadata * metadata, void *client_data);
-static void gst_flac_dec_error_callback (const FLAC__SeekableStreamDecoder *
+static void gst_flac_dec_metadata_callback_stream (const FLAC__StreamDecoder *
+    decoder, const FLAC__StreamMetadata * metadata, void *client_data);
+static void gst_flac_dec_metadata_callback (GstFlacDec * flacdec,
+    const FLAC__StreamMetadata * metadata);
+static void gst_flac_dec_error_callback_seekable (const FLAC__SeekableStreamDecoder *
+    decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+static void gst_flac_dec_error_callback_stream (const FLAC__StreamDecoder *
     decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
 
 GST_BOILERPLATE (GstFlacDec, gst_flac_dec, GstElement, GST_TYPE_ELEMENT);
 #define GST_FLAC_DEC_SRC_CAPS                             \
     "audio/x-raw-int, "                                   \
-    "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", " \
+    "endianness = (int) BYTE_ORDER, "                     \
     "signed = (boolean) true, "                           \
     "width = (int) { 8, 16, 32 }, "                       \
     "depth = (int) { 8, 12, 16, 20, 24, 32 }, "           \
@@ -154,6 +177,16 @@ gst_flac_dec_init (GstFlacDec * flacdec,
       GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate));
   gst_pad_set_activatepull_function (flacdec->sinkpad,
       GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate_pull));
+  gst_pad_set_activatepush_function (flacdec->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate_push));
+  gst_pad_set_query_type_function (flacdec->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flac_dec_get_sink_query_types));
+  gst_pad_set_query_function (flacdec->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flac_dec_sink_query));
+  gst_pad_set_event_function (flacdec->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flac_dec_sink_event));
+  gst_pad_set_chain_function (flacdec->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_flac_dec_chain));
   gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->sinkpad);
 
   flacdec->srcpad = gst_pad_new_from_template (src_template, "src");
@@ -166,29 +199,82 @@ gst_flac_dec_init (GstFlacDec * flacdec,
   gst_pad_use_fixed_caps (flacdec->srcpad);
   gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->srcpad);
 
-  flacdec->decoder = FLAC__seekable_stream_decoder_new ();
+  gst_flac_dec_reset_decoders (flacdec);
+}
+
+static void
+gst_flac_dec_reset_decoders (GstFlacDec * flacdec)
+{
+  if (flacdec->seekable_decoder) {
+    FLAC__seekable_stream_decoder_delete (flacdec->seekable_decoder);
+    flacdec->seekable_decoder = NULL;
+  }
+
+  /* Clean up the stream_decoder */
+  if (flacdec->stream_decoder) {
+    FLAC__stream_decoder_delete (flacdec->stream_decoder);
+    flacdec->stream_decoder = NULL;
+  }
+
+  if (flacdec->adapter) {
+    gst_adapter_clear (flacdec->adapter);
+    g_object_unref (flacdec->adapter);
+    flacdec->adapter = NULL;
+  }
+
   flacdec->segment.last_stop = 0;
+  flacdec->offset = 0;
   flacdec->init = TRUE;
+}
+
+static void
+gst_flac_dec_setup_seekable_decoder (GstFlacDec * dec)
+{
+  gst_flac_dec_reset_decoders (dec);
 
-  FLAC__seekable_stream_decoder_set_read_callback (flacdec->decoder,
-      gst_flac_dec_read);
-  FLAC__seekable_stream_decoder_set_seek_callback (flacdec->decoder,
+  dec->seekable_decoder = FLAC__seekable_stream_decoder_new ();
+    
+  FLAC__seekable_stream_decoder_set_read_callback (dec->seekable_decoder,
+      gst_flac_dec_read_seekable);
+  FLAC__seekable_stream_decoder_set_seek_callback (dec->seekable_decoder,
       gst_flac_dec_seek);
-  FLAC__seekable_stream_decoder_set_tell_callback (flacdec->decoder,
+  FLAC__seekable_stream_decoder_set_tell_callback (dec->seekable_decoder,
       gst_flac_dec_tell);
-  FLAC__seekable_stream_decoder_set_length_callback (flacdec->decoder,
+  FLAC__seekable_stream_decoder_set_length_callback (dec->seekable_decoder,
       gst_flac_dec_length);
-  FLAC__seekable_stream_decoder_set_eof_callback (flacdec->decoder,
+  FLAC__seekable_stream_decoder_set_eof_callback (dec->seekable_decoder,
       gst_flac_dec_eof);
-  FLAC__seekable_stream_decoder_set_write_callback (flacdec->decoder,
-      gst_flac_dec_write);
-  FLAC__seekable_stream_decoder_set_metadata_respond (flacdec->decoder,
+  FLAC__seekable_stream_decoder_set_write_callback (dec->seekable_decoder,
+      gst_flac_dec_write_seekable);
+  FLAC__seekable_stream_decoder_set_metadata_respond (dec->seekable_decoder,
+      FLAC__METADATA_TYPE_VORBIS_COMMENT);
+  FLAC__seekable_stream_decoder_set_metadata_callback (dec->seekable_decoder,
+      gst_flac_dec_metadata_callback_seekable);
+  FLAC__seekable_stream_decoder_set_error_callback (dec->seekable_decoder,
+      gst_flac_dec_error_callback_seekable);
+  FLAC__seekable_stream_decoder_set_client_data (dec->seekable_decoder, dec);
+}
+
+static void
+gst_flac_dec_setup_stream_decoder (GstFlacDec * dec)
+{
+  gst_flac_dec_reset_decoders (dec);
+
+  dec->adapter = gst_adapter_new ();
+
+  dec->stream_decoder = FLAC__stream_decoder_new ();
+
+  FLAC__stream_decoder_set_read_callback (dec->stream_decoder,
+      gst_flac_dec_read_stream);
+  FLAC__stream_decoder_set_write_callback (dec->stream_decoder,
+      gst_flac_dec_write_stream);
+  FLAC__stream_decoder_set_metadata_respond (dec->stream_decoder,
       FLAC__METADATA_TYPE_VORBIS_COMMENT);
-  FLAC__seekable_stream_decoder_set_metadata_callback (flacdec->decoder,
-      gst_flac_dec_metadata_callback);
-  FLAC__seekable_stream_decoder_set_error_callback (flacdec->decoder,
-      gst_flac_dec_error_callback);
-  FLAC__seekable_stream_decoder_set_client_data (flacdec->decoder, flacdec);
+  FLAC__stream_decoder_set_metadata_callback (dec->stream_decoder,
+      gst_flac_dec_metadata_callback_stream);
+  FLAC__stream_decoder_set_error_callback (dec->stream_decoder,
+      gst_flac_dec_error_callback_stream);
+  FLAC__stream_decoder_set_client_data (dec->stream_decoder, dec);
 }
 
 static void
@@ -198,9 +284,7 @@ gst_flac_dec_finalize (GObject * object)
 
   flacdec = GST_FLAC_DEC (object);
 
-  if (flacdec->decoder)
-    FLAC__seekable_stream_decoder_delete (flacdec->decoder);
-  flacdec->decoder = NULL;
+  gst_flac_dec_reset_decoders (flacdec);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -415,13 +499,9 @@ gst_flac_dec_scan_for_last_block (GstFla
 }
 
 static void
-gst_flac_dec_metadata_callback (const FLAC__SeekableStreamDecoder * decoder,
-    const FLAC__StreamMetadata * metadata, void *client_data)
+gst_flac_dec_metadata_callback (GstFlacDec * flacdec,
+    const FLAC__StreamMetadata * metadata)
 {
-  GstFlacDec *flacdec;
-
-  flacdec = GST_FLAC_DEC (client_data);
-
   switch (metadata->type) {
     case FLAC__METADATA_TYPE_STREAMINFO:{
       gint64 samples;
@@ -435,7 +515,8 @@ gst_flac_dec_metadata_callback (const FL
       GST_DEBUG_OBJECT (flacdec, "blocksize: min=%u, max=%u",
           flacdec->min_blocksize, flacdec->max_blocksize);
 
-      if (samples == 0) {
+      /* Only scan for last block in pull-mode, since it uses pull_range() */
+      if (samples == 0 && flacdec->seekable_decoder) {
         gst_flac_dec_scan_for_last_block (flacdec, &samples);
       }
 
@@ -458,18 +539,33 @@ gst_flac_dec_metadata_callback (const FL
 }
 
 static void
-gst_flac_dec_error_callback (const FLAC__SeekableStreamDecoder * decoder,
-    FLAC__StreamDecoderErrorStatus status, void *client_data)
+gst_flac_dec_metadata_callback_seekable (const FLAC__SeekableStreamDecoder * d,
+    const FLAC__StreamMetadata * metadata, void * client_data)
 {
-  GstFlacDec *flacdec;
-  gchar *error;
+  GstFlacDec *dec = GST_FLAC_DEC (client_data);
 
-  flacdec = GST_FLAC_DEC (client_data);
+  gst_flac_dec_metadata_callback (dec, metadata);
+}
+
+static void
+gst_flac_dec_metadata_callback_stream (const FLAC__StreamDecoder * decoder,
+    const FLAC__StreamMetadata * metadata, void * client_data)
+{
+  GstFlacDec *dec = GST_FLAC_DEC (client_data);
+
+  gst_flac_dec_metadata_callback (dec, metadata);
+}
+
+static void
+gst_flac_dec_error_callback (GstFlacDec * dec,
+    FLAC__StreamDecoderErrorStatus status)
+{
+  const gchar *error;
 
   switch (status) {
     case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
-      error = "lost sync";
-      break;
+      /* Ignore this error and keep processing */
+      return;
     case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
       error = "bad header";
       break;
@@ -481,8 +577,22 @@ gst_flac_dec_error_callback (const FLAC_
       break;
   }
 
-  GST_ELEMENT_ERROR (flacdec, STREAM, DECODE, (NULL), (error));
-  flacdec->last_flow = GST_FLOW_ERROR;
+  GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status));
+  dec->last_flow = GST_FLOW_ERROR;
+}
+
+static void
+gst_flac_dec_error_callback_seekable (const FLAC__SeekableStreamDecoder * d,
+    FLAC__StreamDecoderErrorStatus status, void * client_data)
+{
+  gst_flac_dec_error_callback (GST_FLAC_DEC (client_data), status);
+}
+
+static void
+gst_flac_dec_error_callback_stream (const FLAC__StreamDecoder * d,
+    FLAC__StreamDecoderErrorStatus status, void * client_data)
+{
+  gst_flac_dec_error_callback (GST_FLAC_DEC (client_data), status);
 }
 
 static FLAC__SeekableStreamDecoderSeekStatus
@@ -570,7 +680,7 @@ gst_flac_dec_eof (const FLAC__SeekableSt
 }
 
 static FLAC__SeekableStreamDecoderReadStatus
-gst_flac_dec_read (const FLAC__SeekableStreamDecoder * decoder,
+gst_flac_dec_read_seekable (const FLAC__SeekableStreamDecoder * decoder,
     FLAC__byte buffer[], unsigned *bytes, void *client_data)
 {
   GstFlacDec *flacdec;
@@ -592,13 +702,35 @@ gst_flac_dec_read (const FLAC__SeekableS
   return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
 }
 
+static FLAC__StreamDecoderReadStatus
+gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
+    FLAC__byte buffer[], unsigned *bytes, void *client_data)
+{
+  GstFlacDec *dec = GST_FLAC_DEC (client_data);
+  guint len;
+
+  len = MIN (gst_adapter_available (dec->adapter), *bytes);
+
+  if (len == 0) {
+    GST_LOG_OBJECT (dec, "0 bytes available at the moment");
+    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+  }
+
+  GST_LOG_OBJECT (dec, "feeding %u bytes to decoder (available=%u, bytes=%u)",
+      len, gst_adapter_available (dec->adapter), *bytes);
+  memcpy (buffer, gst_adapter_peek (dec->adapter, len), len);
+  *bytes = len;
+
+  gst_adapter_flush (dec->adapter, len);
+
+  return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
 static FLAC__StreamDecoderWriteStatus
-gst_flac_dec_write (const FLAC__SeekableStreamDecoder * decoder,
-    const FLAC__Frame * frame,
-    const FLAC__int32 * const buffer[], void *client_data)
+gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
+    const FLAC__int32 * const buffer[])
 {
   GstFlowReturn ret = GST_FLOW_OK;
-  GstFlacDec *flacdec;
   GstBuffer *outbuf;
   guint depth = frame->header.bits_per_sample;
   guint width;
@@ -606,8 +738,6 @@ gst_flac_dec_write (const FLAC__Seekable
   guint samples = frame->header.blocksize;
   guint j, i;
 
-  flacdec = GST_FLAC_DEC (client_data);
-
   switch (depth) {
     case 8:
       width = 8;
@@ -737,6 +867,22 @@ done:
   return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
 }
 
+static FLAC__StreamDecoderWriteStatus
+gst_flac_dec_write_seekable (const FLAC__SeekableStreamDecoder * decoder,
+    const FLAC__Frame * frame,
+    const FLAC__int32 * const buffer[], void *client_data)
+{
+ return gst_flac_dec_write (GST_FLAC_DEC (client_data), frame, buffer);
+}
+
+static FLAC__StreamDecoderWriteStatus
+gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
+    const FLAC__Frame * frame,
+    const FLAC__int32 * const buffer[], void *client_data)
+{
+ return gst_flac_dec_write (GST_FLAC_DEC (client_data), frame, buffer);
+}
+
 static void
 gst_flac_dec_loop (GstPad * sinkpad)
 {
@@ -749,22 +895,22 @@ gst_flac_dec_loop (GstPad * sinkpad)
 
   if (flacdec->init) {
     GST_DEBUG_OBJECT (flacdec, "initializing decoder");
-    s = FLAC__seekable_stream_decoder_init (flacdec->decoder);
+    s = FLAC__seekable_stream_decoder_init (flacdec->seekable_decoder);
     if (s != FLAC__SEEKABLE_STREAM_DECODER_OK)
       goto analyze_state;
-    /*    FLAC__seekable_stream_decoder_process_metadata (flacdec->decoder); */
+    /*    FLAC__seekable_stream_decoder_process_metadata (flacdec->seekable_decoder); */
     flacdec->init = FALSE;
   }
 
   flacdec->last_flow = GST_FLOW_OK;
 
   GST_LOG_OBJECT (flacdec, "processing single");
-  FLAC__seekable_stream_decoder_process_single (flacdec->decoder);
+  FLAC__seekable_stream_decoder_process_single (flacdec->seekable_decoder);
 
 analyze_state:
 
   GST_LOG_OBJECT (flacdec, "done processing, checking encoder state");
-  s = FLAC__seekable_stream_decoder_get_state (flacdec->decoder);
+  s = FLAC__seekable_stream_decoder_get_state (flacdec->seekable_decoder);
   switch (s) {
     case FLAC__SEEKABLE_STREAM_DECODER_OK:
     case FLAC__SEEKABLE_STREAM_DECODER_SEEKING:{
@@ -797,7 +943,7 @@ analyze_state:
 
     case FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM:{
       GST_DEBUG_OBJECT (flacdec, "EOS");
-      FLAC__seekable_stream_decoder_reset (flacdec->decoder);
+      FLAC__seekable_stream_decoder_reset (flacdec->seekable_decoder);
 
       if ((flacdec->segment.flags & GST_SEEK_FLAG_SEGMENT) != 0) {
         if (flacdec->segment.duration > 0) {
@@ -862,6 +1008,226 @@ pause:
 }
 
 static gboolean
+gst_flac_dec_sink_event (GstPad * pad, GstEvent * event)
+{
+  GstFlacDec *dec;
+  gboolean res;
+
+  dec = GST_FLAC_DEC (gst_pad_get_parent (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_STOP: {
+      if (dec->stream_decoder) {
+        FLAC__stream_decoder_flush (dec->stream_decoder);
+        gst_adapter_clear (dec->adapter);
+      }
+      res = gst_pad_push_event (dec->srcpad, event);
+      break;
+    }
+    case GST_EVENT_NEWSEGMENT: {
+      GstFormat fmt;
+
+      gst_event_parse_new_segment (event, NULL, NULL, &fmt, NULL, NULL, NULL);
+      if (fmt == GST_FORMAT_TIME) {
+        GST_DEBUG_OBJECT (dec, "newsegment event in TIME format => framed");
+        dec->framed = TRUE;
+        res = gst_pad_push_event (dec->srcpad, event);
+        dec->need_newsegment = FALSE;
+      } else if (fmt == GST_FORMAT_BYTES || TRUE) {
+        GST_DEBUG_OBJECT (dec, "newsegment event in %s format => not framed",
+            gst_format_get_name (fmt));
+        dec->framed = FALSE;
+        dec->need_newsegment = TRUE;
+        gst_event_unref (event);
+        res = TRUE;
+      }
+      break;
+    }
+    case GST_EVENT_EOS: {
+      GST_LOG_OBJECT (dec, "EOS, with %u bytes available in adapter",
+          gst_adapter_available (dec->adapter));
+      if (gst_adapter_available (dec->adapter) > 0) {
+        FLAC__stream_decoder_process_until_end_of_stream (dec->stream_decoder);
+      }
+      FLAC__stream_decoder_flush (dec->stream_decoder);
+      gst_adapter_clear (dec->adapter);
+      res = gst_pad_push_event (dec->srcpad, event);
+      break;
+    }
+    default:
+      res = gst_pad_event_default (pad, event);
+      break;
+  }
+
+  gst_object_unref (dec);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_flac_dec_chain (GstPad * pad, GstBuffer * buf)
+{
+  FLAC__SeekableStreamDecoderState s;
+  GstFlacDec *dec;
+
+  dec = GST_FLAC_DEC (GST_PAD_PARENT (pad));
+
+  GST_LOG_OBJECT (dec, "buffer with ts=%" GST_TIME_FORMAT ", end_offset=%"
+      G_GINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+      GST_BUFFER_OFFSET_END (buf));
+
+  if (dec->init) {
+    GST_DEBUG_OBJECT (dec, "initializing decoder");
+    s = FLAC__stream_decoder_init (dec->stream_decoder);
+    if (s != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) {
+      GST_ELEMENT_ERROR (GST_ELEMENT (dec), LIBRARY, INIT, (NULL), (NULL));
+      return GST_FLOW_ERROR;
+    }
+    GST_DEBUG_OBJECT (dec, "initialized (framed=%d)", dec->framed);
+    dec->init = FALSE;
+  }
+
+  if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
+    /* Clear the adapter and the decoder */
+    gst_adapter_clear (dec->adapter);
+    FLAC__stream_decoder_flush (dec->stream_decoder);
+  }
+
+  gst_adapter_push (dec->adapter, buf);
+  buf = NULL;
+  
+  dec->last_flow = GST_FLOW_OK;
+
+  if (!dec->framed) {
+    /* wait until we have at least 64kB because libflac's StreamDecoder
+     * interface is a bit dumb it seems (if we don't have as much data as
+     * it wants it will call our read callback repeatedly and the only
+     * way to stop that is to error out or EOS, which will affect the
+     * decoder state). Requiring MAX_BLOCK_SIZE should make sure it
+     * always gets enough data to decode at least one block */
+    while (gst_adapter_available (dec->adapter) >= FLAC__MAX_BLOCK_SIZE &&
+        dec->last_flow == GST_FLOW_OK) {
+      GST_LOG_OBJECT (dec, "%u bytes available",
+          gst_adapter_available (dec->adapter));
+      if (!FLAC__stream_decoder_process_single (dec->stream_decoder)) {
+        GST_DEBUG_OBJECT (dec, "process_single failed");
+        break;
+      }
+    }
+  } else {
+    /* framed - there should always be enough data to decode something */
+    GST_LOG_OBJECT (dec, "%u bytes available",
+        gst_adapter_available (dec->adapter));
+    if (!FLAC__stream_decoder_process_single (dec->stream_decoder)) {
+      GST_DEBUG_OBJECT (dec, "process_single failed");
+    }
+  }
+
+  return dec->last_flow;
+}
+
+static gboolean
+gst_flac_dec_convert_sink (GstFlacDec *dec, GstFormat src_format,
+    gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
+{
+  gboolean res = TRUE;
+
+  if (dec->width == 0 || dec->channels == 0 || dec->sample_rate == 0) {
+    /* no frame decoded yet */
+    GST_DEBUG_OBJECT (dec, "cannot convert: not set up yet");
+    return FALSE;
+  }
+
+  switch (src_format) {
+    case GST_FORMAT_BYTES:{
+      res = FALSE;
+      break;
+    }
+    case GST_FORMAT_DEFAULT:
+      switch (*dest_format) {
+        case GST_FORMAT_BYTES:
+          res = FALSE;
+          break;
+        case GST_FORMAT_TIME:
+          /* granulepos = sample */
+          *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
+              dec->sample_rate);
+          break;
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    case GST_FORMAT_TIME:
+      switch (*dest_format) {
+        case GST_FORMAT_BYTES:
+          res = FALSE;
+          break;
+        case GST_FORMAT_DEFAULT:
+          *dest_value = gst_util_uint64_scale_int (src_value,
+              dec->sample_rate, GST_SECOND);
+          break;
+        default:
+          res = FALSE;
+          break;
+      }
+      break;
+    default:
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+static const GstQueryType *
+gst_flac_dec_get_sink_query_types (GstPad * pad)
+{
+  static const GstQueryType types[] = {
+    GST_QUERY_CONVERT,
+    0,
+  };
+
+  return types;
+}
+
+static gboolean
+gst_flac_dec_sink_query (GstPad * pad, GstQuery * query)
+{
+  GstFlacDec *dec;
+  gboolean res = FALSE;
+
+  dec = GST_FLAC_DEC (gst_pad_get_parent (pad));
+
+  GST_LOG_OBJECT (dec, "%s query", GST_QUERY_TYPE_NAME (query));
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONVERT:{
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
+
+      res = gst_flac_dec_convert_sink (dec, src_fmt, src_val, &dest_fmt,
+          &dest_val);
+
+      if (res) {
+        gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+      }
+      GST_LOG_OBJECT (dec, "conversion %s", (res) ? "ok" : "FAILED");
+      break;
+    }
+
+    default:{
+      res = gst_pad_query_default (pad, query);
+      break;
+    }
+  }
+
+  gst_object_unref (dec);
+  return res;
+}
+
+static gboolean
 gst_flac_dec_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
     GstFormat * dest_format, gint64 * dest_value)
 {
@@ -936,6 +1302,7 @@ gst_flac_dec_get_src_query_types (GstPad
   static const GstQueryType types[] = {
     GST_QUERY_POSITION,
     GST_QUERY_DURATION,
+    GST_QUERY_CONVERT,
     0,
   };
 
@@ -959,6 +1326,10 @@ gst_flac_dec_src_query (GstPad * pad, Gs
 
       gst_query_parse_position (query, &fmt, NULL);
 
+      /* there might be a demuxer in front of us who can handle this */
+      if (fmt == GST_FORMAT_TIME && (res = gst_pad_query (peer, query)))
+        break;
+
       if (fmt != GST_FORMAT_DEFAULT) {
         if (!gst_flac_dec_convert_src (flacdec->srcpad, GST_FORMAT_DEFAULT,
                 flacdec->segment.last_stop, &fmt, &pos)) {
@@ -1027,7 +1398,7 @@ gst_flac_dec_src_query (GstPad * pad, Gs
       GstFormat src_fmt, dest_fmt;
       gint64 src_val, dest_val;
 
-      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
 
       res = gst_flac_dec_convert_src (pad, src_fmt, src_val, &dest_fmt,
           &dest_val);
@@ -1101,6 +1472,11 @@ gst_flac_dec_handle_seek_event (GstFlacD
   gint64 start;
   gint64 stop;
 
+  if (flacdec->seekable_decoder == NULL) {
+    GST_DEBUG_OBJECT (flacdec, "seeking in streaming mode not implemented yet");
+    return FALSE;
+  }
+
   gst_event_parse_seek (event, &rate, &seek_format, &seek_flags, &start_type,
       &start, &stop_type, &stop);
 
@@ -1166,12 +1542,11 @@ gst_flac_dec_handle_seek_event (GstFlacD
 
   flacdec->seeking = TRUE;
 
-  seek_ok = FLAC__seekable_stream_decoder_seek_absolute (flacdec->decoder,
+  seek_ok = FLAC__seekable_stream_decoder_seek_absolute (flacdec->seekable_decoder,
       segment.start);
 
   flacdec->seeking = FALSE;
 
-  /* FIXME: support segment seeks */
   if (flush) {
     gst_pad_push_event (flacdec->srcpad, gst_event_new_flush_stop ());
   }
@@ -1242,15 +1617,28 @@ gst_flac_dec_sink_activate (GstPad * sin
   if (gst_pad_check_pull_range (sinkpad))
     return gst_pad_activate_pull (sinkpad, TRUE);
 
-  return FALSE;
+  return gst_pad_activate_push (sinkpad, TRUE);
+}
+
+static gboolean
+gst_flac_dec_sink_activate_push (GstPad * sinkpad, gboolean active)
+{
+  GstFlacDec *dec = GST_FLAC_DEC (GST_OBJECT_PARENT (sinkpad));
+
+  gst_flac_dec_setup_stream_decoder (dec);
+  return TRUE;
 }
 
 static gboolean
 gst_flac_dec_sink_activate_pull (GstPad * sinkpad, gboolean active)
 {
   if (active) {
-    /* if we have a scheduler we can start the task */
-    GST_FLAC_DEC (GST_OBJECT_PARENT (sinkpad))->offset = 0;
+    GstFlacDec *flacdec;
+
+    flacdec = GST_FLAC_DEC (GST_PAD_PARENT (sinkpad));
+
+    flacdec->offset = 0;
+    gst_flac_dec_setup_seekable_decoder (flacdec);
     return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flac_dec_loop,
         sinkpad);
   } else {
@@ -1273,9 +1661,6 @@ gst_flac_dec_change_state (GstElement * 
       flacdec->depth = 0;
       flacdec->width = 0;
       flacdec->sample_rate = 0;
-      if (flacdec->init == FALSE) {
-        FLAC__seekable_stream_decoder_reset (flacdec->decoder);
-      }
       gst_segment_init (&flacdec->segment, GST_FORMAT_DEFAULT);
       break;
     default:
@@ -1289,6 +1674,7 @@ gst_flac_dec_change_state (GstElement * 
   switch (transition) {
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       gst_segment_init (&flacdec->segment, GST_FORMAT_UNDEFINED);
+      gst_flac_dec_reset_decoders (flacdec);
       break;
     default:
       break;
Index: gstflacdec.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/ext/flac/gstflacdec.h,v
retrieving revision 1.20
diff -u -p -r1.20 gstflacdec.h
--- gstflacdec.h	6 May 2006 09:01:34 -0000	1.20
+++ gstflacdec.h	17 Jun 2006 11:22:28 -0000
@@ -23,6 +23,7 @@
 
 
 #include <gst/gst.h>
+#include <gst/base/gstadapter.h>
 
 #include <FLAC/all.h>
 
@@ -40,7 +41,11 @@ typedef struct _GstFlacDecClass GstFlacD
 struct _GstFlacDec {
   GstElement     element;
 
-  FLAC__SeekableStreamDecoder *decoder;
+  FLAC__SeekableStreamDecoder *seekable_decoder; /* for pull-based operation  */
+
+  FLAC__StreamDecoder         *stream_decoder;   /* for chain-based operation */
+  GstAdapter                  *adapter;
+  gboolean                     framed;
 
   GstPad        *sinkpad;
   GstPad        *srcpad;
Index: Makefile.am
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/ext/flac/Makefile.am,v
retrieving revision 1.17
diff -u -p -r1.17 Makefile.am
--- Makefile.am	11 Jun 2006 13:57:19 -0000	1.17
+++ Makefile.am	17 Jun 2006 11:22:28 -0000
@@ -1,10 +1,10 @@
 plugin_LTLIBRARIES = libgstflac.la
 
 libgstflac_la_SOURCES = gstflac.c gstflacdec.c gstflacenc.c
-libgstflac_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
+libgstflac_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
 libgstflac_la_LIBADD = \
 	$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
-	$(GST_LIBS) $(FLAC_LIBS)
+	$(GST_BASE_LIBS) $(GST_LIBS) $(FLAC_LIBS)
 libgstflac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 
 noinst_HEADERS = gstflacenc.h gstflacdec.h
