summaryrefslogtreecommitdiff
path: root/ext/flac
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim.muller@collabora.co.uk>2011-10-09 16:18:09 +0100
committerTim-Philipp Müller <tim.muller@collabora.co.uk>2011-10-30 17:39:40 +0000
commit92361863e6f4fabc919d9eeeac2370f0b859908a (patch)
tree50055e14126f7745235aa600614fbe643b2c22a9 /ext/flac
parent9cd17092d8441d6018bc1357b7693d9c1313e17c (diff)
downloadgstreamer-plugins-good-92361863e6f4fabc919d9eeeac2370f0b859908a.tar.gz
flacdec: naive port to GstAudioDecoder
This would probably have been too invasive to do in the 0.10 branch, with all the pull-mode and parser handling code in there.
Diffstat (limited to 'ext/flac')
-rw-r--r--ext/flac/gstflacdec.c728
-rw-r--r--ext/flac/gstflacdec.h28
2 files changed, 123 insertions, 633 deletions
diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c
index e35672aa7..7ae17547c 100644
--- a/ext/flac/gstflacdec.c
+++ b/ext/flac/gstflacdec.c
@@ -45,8 +45,6 @@
#include "gstflacdec.h"
#include <gst/gst-i18n-plugin.h>
-#include <gst/gsttagsetter.h>
-#include <gst/base/gsttypefindhelper.h>
#include <gst/audio/multichannel.h>
#include <gst/tag/tag.h>
@@ -95,25 +93,6 @@ static const GstAudioChannelPosition channel_positions[8][8] = {
GST_DEBUG_CATEGORY_STATIC (flacdec_debug);
#define GST_CAT_DEFAULT flacdec_debug
-static void gst_flac_dec_finalize (GObject * object);
-
-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);
-static gboolean gst_flac_dec_sink_activate (GstPad * sinkpad);
-static gboolean gst_flac_dec_sink_activate_push (GstPad * sinkpad,
- gboolean active);
-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_decoder (GstFlacDec * flacdec);
-
static FLAC__StreamDecoderReadStatus
gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
FLAC__byte buffer[], size_t * bytes, void *client_data);
@@ -126,8 +105,14 @@ static void gst_flac_dec_metadata_cb (const FLAC__StreamDecoder *
static void gst_flac_dec_error_cb (const FLAC__StreamDecoder *
decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
-#define gst_flac_dec_parent_class parent_class
-G_DEFINE_TYPE (GstFlacDec, gst_flac_dec, GST_TYPE_ELEMENT);
+static void gst_flac_dec_flush (GstAudioDecoder * audio_dec, gboolean hard);
+static gboolean gst_flac_dec_set_format (GstAudioDecoder * dec, GstCaps * caps);
+static gboolean gst_flac_dec_start (GstAudioDecoder * dec);
+static gboolean gst_flac_dec_stop (GstAudioDecoder * dec);
+static GstFlowReturn gst_flac_dec_handle_frame (GstAudioDecoder * audio_dec,
+ GstBuffer * buf);
+
+G_DEFINE_TYPE (GstFlacDec, gst_flac_dec, GST_TYPE_AUDIO_DECODER);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define FORMATS "{ S8LE, S16LE, S32LE } "
@@ -144,6 +129,12 @@ G_DEFINE_TYPE (GstFlacDec, gst_flac_dec, GST_TYPE_ELEMENT);
"rate = (int) [ 1, 655350 ], " \
"channels = (int) [ 1, 8 ]"
+#define GST_FLAC_DEC_SINK_CAPS \
+ "audio/x-flac, " \
+ "framed = (boolean) true, " \
+ "rate = (int) [ 1, 655350 ], " \
+ "channels = (int) [ 1, 8 ]"
+
static GstStaticPadTemplate flac_dec_src_factory =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
@@ -153,24 +144,25 @@ static GstStaticPadTemplate flac_dec_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-flac")
- );
+ GST_STATIC_CAPS (GST_FLAC_DEC_SINK_CAPS));
static void
gst_flac_dec_class_init (GstFlacDecClass * klass)
{
+ GstAudioDecoderClass *audiodecoder_class;
GstElementClass *gstelement_class;
- GObjectClass *gobject_class;
+ audiodecoder_class = (GstAudioDecoderClass *) klass;
gstelement_class = (GstElementClass *) klass;
- gobject_class = (GObjectClass *) klass;
GST_DEBUG_CATEGORY_INIT (flacdec_debug, "flacdec", 0, "flac decoder");
- gobject_class->finalize = gst_flac_dec_finalize;
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_flac_dec_change_state);
+ audiodecoder_class->stop = GST_DEBUG_FUNCPTR (gst_flac_dec_stop);
+ audiodecoder_class->start = GST_DEBUG_FUNCPTR (gst_flac_dec_start);
+ audiodecoder_class->flush = GST_DEBUG_FUNCPTR (gst_flac_dec_flush);
+ audiodecoder_class->set_format = GST_DEBUG_FUNCPTR (gst_flac_dec_set_format);
+ audiodecoder_class->handle_frame =
+ GST_DEBUG_FUNCPTR (gst_flac_dec_handle_frame);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&flac_dec_src_factory));
@@ -178,96 +170,86 @@ gst_flac_dec_class_init (GstFlacDecClass * klass)
gst_static_pad_template_get (&flac_dec_sink_factory));
gst_element_class_set_details_simple (gstelement_class, "FLAC audio decoder",
- "Codec/Decoder/Audio",
- "Decodes FLAC lossless audio streams", "Wim Taymans <wim@fluendo.com>");
+ "Codec/Decoder/Audio", "Decodes FLAC lossless audio streams",
+ "Tim-Philipp Müller <tim@centricular.net>, "
+ "Wim Taymans <wim.taymans@gmail.com>");
}
static void
gst_flac_dec_init (GstFlacDec * flacdec)
{
- flacdec->sinkpad =
- gst_pad_new_from_static_template (&flac_dec_sink_factory, "sink");
- gst_pad_set_activate_function (flacdec->sinkpad,
- GST_DEBUG_FUNCPTR (gst_flac_dec_sink_activate));
- 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_static_template (&flac_dec_src_factory, "src");
- gst_pad_set_query_type_function (flacdec->srcpad,
- GST_DEBUG_FUNCPTR (gst_flac_dec_get_src_query_types));
- gst_pad_set_query_function (flacdec->srcpad,
- GST_DEBUG_FUNCPTR (gst_flac_dec_src_query));
- gst_pad_use_fixed_caps (flacdec->srcpad);
- gst_element_add_pad (GST_ELEMENT (flacdec), flacdec->srcpad);
-
- gst_flac_dec_reset_decoders (flacdec);
+ /* nothing to do here */
}
-static void
-gst_flac_dec_reset_decoders (GstFlacDec * flacdec)
+static gboolean
+gst_flac_dec_start (GstAudioDecoder * audio_dec)
{
- /* Clean up the decoder */
- if (flacdec->decoder) {
- FLAC__stream_decoder_delete (flacdec->decoder);
- flacdec->decoder = NULL;
- }
-
- if (flacdec->adapter) {
- gst_adapter_clear (flacdec->adapter);
- g_object_unref (flacdec->adapter);
- flacdec->adapter = NULL;
- }
-
- if (flacdec->tags) {
- gst_tag_list_free (flacdec->tags);
- flacdec->tags = NULL;
- }
-
- flacdec->segment.position = 0;
- flacdec->init = TRUE;
-}
+ FLAC__StreamDecoderInitStatus s;
+ GstFlacDec *dec;
-static void
-gst_flac_dec_setup_decoder (GstFlacDec * dec)
-{
- gst_flac_dec_reset_decoders (dec);
+ dec = GST_FLAC_DEC (audio_dec);
+ ///////////// FIXME:
dec->tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, "FLAC", NULL);
dec->adapter = gst_adapter_new ();
dec->decoder = FLAC__stream_decoder_new ();
- /* no point calculating since it's never checked here */
+ /* no point calculating MD5 since it's never checked here */
FLAC__stream_decoder_set_md5_checking (dec->decoder, false);
FLAC__stream_decoder_set_metadata_respond (dec->decoder,
FLAC__METADATA_TYPE_VORBIS_COMMENT);
FLAC__stream_decoder_set_metadata_respond (dec->decoder,
FLAC__METADATA_TYPE_PICTURE);
+
+ GST_DEBUG_OBJECT (dec, "initializing decoder");
+ s = FLAC__stream_decoder_init_stream (dec->decoder,
+ gst_flac_dec_read_stream, NULL, NULL, NULL, NULL,
+ gst_flac_dec_write_stream, gst_flac_dec_metadata_cb,
+ gst_flac_dec_error_cb, dec);
+
+ if (s != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ GST_ELEMENT_ERROR (GST_ELEMENT (dec), LIBRARY, INIT, (NULL), (NULL));
+ return FALSE;
+ }
+
+ dec->got_headers = FALSE;
+
+ return TRUE;
}
-static void
-gst_flac_dec_finalize (GObject * object)
+static gboolean
+gst_flac_dec_stop (GstAudioDecoder * dec)
{
- GstFlacDec *flacdec;
+ GstFlacDec *flacdec = GST_FLAC_DEC (dec);
+
+ if (flacdec->decoder) {
+ FLAC__stream_decoder_delete (flacdec->decoder);
+ flacdec->decoder = NULL;
+ }
- flacdec = GST_FLAC_DEC (object);
+ if (flacdec->adapter) {
+ gst_adapter_clear (flacdec->adapter);
+ g_object_unref (flacdec->adapter);
+ flacdec->adapter = NULL;
+ }
- gst_flac_dec_reset_decoders (flacdec);
+ if (flacdec->tags) {
+ gst_tag_list_free (flacdec->tags);
+ flacdec->tags = NULL;
+ }
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ return TRUE;
}
+static gboolean
+gst_flac_dec_set_format (GstAudioDecoder * dec, GstCaps * caps)
+{
+ /* if stream headers are present we could process them here already */
+ GST_LOG_OBJECT (dec, "sink caps: %" GST_PTR_FORMAT, caps);
+ return TRUE;
+}
static gboolean
gst_flac_dec_update_metadata (GstFlacDec * flacdec,
@@ -437,6 +419,7 @@ gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, guint8 * data, guint size,
return TRUE;
}
+/* FIXME: let parser extract tags */
static void
gst_flac_extract_picture_buffer (GstFlacDec * dec,
const FLAC__StreamMetadata * metadata)
@@ -459,7 +442,8 @@ gst_flac_extract_picture_buffer (GstFlacDec * dec,
picture.data_length, picture.type);
if (!gst_tag_list_is_empty (tags)) {
- gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, tags);
+ gst_element_found_tags_for_pad (GST_ELEMENT (dec),
+ GST_AUDIO_DECODER_SRC_PAD (dec), tags);
} else {
GST_DEBUG_OBJECT (dec, "problem parsing PICTURE block, skipping");
gst_tag_list_free (tags);
@@ -502,26 +486,6 @@ gst_flac_dec_metadata_cb (const FLAC__StreamDecoder * decoder,
flacdec->width);
GST_DEBUG_OBJECT (flacdec, "total samples = %" G_GINT64_FORMAT, samples);
-
- /* in framed mode the demuxer/parser upstream has already pushed a
- * newsegment event in TIME format which we've passed on */
- if (samples > 0 && !flacdec->framed) {
- gint64 duration;
- GstSegment seg;
-
- flacdec->segment.duration = samples;
-
- /* convert duration to time */
- duration = gst_util_uint64_scale_int (samples, GST_SECOND,
- flacdec->sample_rate);
-
- gst_segment_init (&seg, GST_FORMAT_TIME);
- seg.rate = flacdec->segment.rate;
- seg.applied_rate = flacdec->segment.applied_rate;
- seg.start = 0;
- seg.stop = duration;
- seg.time = 0;
- }
break;
}
case FLAC__METADATA_TYPE_PICTURE:{
@@ -600,24 +564,12 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
guint channels = frame->header.channels;
guint samples = frame->header.blocksize;
guint j, i;
- GstClockTime next;
gpointer data;
gsize size;
const gchar *format;
GST_LOG_OBJECT (flacdec, "samples in frame header: %d", samples);
- /* if a DEFAULT segment is configured, don't send samples past the end
- * of the segment */
- if (flacdec->segment.format == GST_FORMAT_DEFAULT &&
- flacdec->segment.stop != -1 &&
- flacdec->segment.position >= 0 &&
- flacdec->segment.position + samples > flacdec->segment.stop) {
- samples = flacdec->segment.stop - flacdec->segment.position;
- GST_DEBUG_OBJECT (flacdec,
- "clipping last buffer to %d samples because of segment", samples);
- }
-
if (depth == 0) {
if (flacdec->depth < 4 || flacdec->depth > 32) {
GST_ERROR_OBJECT (flacdec, "unsupported depth %d from STREAMINFO",
@@ -667,7 +619,7 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
}
}
- if (!gst_pad_has_current_caps (flacdec->srcpad)) {
+ if (!gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (flacdec))) {
GstCaps *caps;
GST_DEBUG_OBJECT (flacdec, "Negotiating %d Hz @ %d channels",
@@ -689,31 +641,19 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
flacdec->channels = channels;
flacdec->sample_rate = sample_rate;
- gst_pad_set_caps (flacdec->srcpad, caps);
+ gst_audio_decoder_set_outcaps (GST_AUDIO_DECODER (flacdec), caps);
gst_caps_unref (caps);
}
if (flacdec->tags) {
- gst_element_found_tags_for_pad (GST_ELEMENT (flacdec), flacdec->srcpad,
- flacdec->tags);
+ gst_element_found_tags_for_pad (GST_ELEMENT (flacdec),
+ GST_AUDIO_DECODER_SRC_PAD (flacdec), flacdec->tags);
flacdec->tags = NULL;
}
GST_LOG_OBJECT (flacdec, "alloc_buffer_and_set_caps");
outbuf = gst_buffer_new_allocate (NULL, samples * channels * (width / 8), 0);
- GST_BUFFER_OFFSET (outbuf) = flacdec->segment.position;
-
- GST_BUFFER_TIMESTAMP (outbuf) =
- gst_util_uint64_scale_int (flacdec->segment.position, GST_SECOND,
- frame->header.sample_rate);
-
- /* get next timestamp to calculate the duration */
- next = gst_util_uint64_scale_int (flacdec->segment.position + samples,
- GST_SECOND, frame->header.sample_rate);
-
- GST_BUFFER_DURATION (outbuf) = next - GST_BUFFER_TIMESTAMP (outbuf);
-
data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_WRITE);
if (width == 8) {
gint8 *outbuffer = (gint8 *) data;
@@ -750,21 +690,17 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
- ret = gst_pad_push (flacdec->srcpad, outbuf);
- GST_DEBUG_OBJECT (flacdec, "returned %s", gst_flow_get_name (ret));
- flacdec->segment.position += samples;
+ ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (flacdec), outbuf, 1);
- if (ret != GST_FLOW_OK) {
- GST_DEBUG_OBJECT (flacdec, "gst_pad_push() returned %s",
- gst_flow_get_name (ret));
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ GST_DEBUG_OBJECT (flacdec, "finish_frame flow %s", gst_flow_get_name (ret));
}
done:
-
- /* we act on the flow return value later in the loop function, as we don't
- * want to mess up the internal decoder state by returning ABORT when the
- * error is in fact non-fatal (like a pad in flushing mode) and we want
+ /* we act on the flow return value later in the handle_frame function, as we
+ * don't want to mess up the internal decoder state by returning ABORT when
+ * the error is in fact non-fatal (like a pad in flushing mode) and we want
* to continue later. So just pretend everything's dandy and act later. */
flacdec->last_flow = ret;
@@ -779,82 +715,22 @@ gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
return gst_flac_dec_write (GST_FLAC_DEC (client_data), frame, buffer);
}
-static gboolean
-gst_flac_dec_sink_event (GstPad * pad, GstEvent * event)
+static void
+gst_flac_dec_flush (GstAudioDecoder * audio_dec, gboolean hard)
{
- GstFlacDec *dec;
- gboolean res;
+ GstFlacDec *dec = GST_FLAC_DEC (audio_dec);
- dec = GST_FLAC_DEC (gst_pad_get_parent (pad));
+ if (!hard) {
+ guint available = gst_adapter_available (dec->adapter);
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_CAPS:
- res = TRUE;
- gst_event_unref (event);
- break;
- case GST_EVENT_FLUSH_STOP:{
- if (dec->init == FALSE) {
- FLAC__stream_decoder_flush (dec->decoder);
- gst_adapter_clear (dec->adapter);
- }
- res = gst_pad_push_event (dec->srcpad, event);
- break;
- }
- case GST_EVENT_SEGMENT:{
- GstSegment seg;
- gint64 start, stop;
-
- gst_event_copy_segment (event, &seg);
-
- if (seg.format == GST_FORMAT_TIME) {
- GstFormat dformat = GST_FORMAT_DEFAULT;
-
- GST_DEBUG_OBJECT (dec, "newsegment event in TIME format => framed");
- dec->framed = TRUE;
- res = gst_pad_push_event (dec->srcpad, event);
-
- /* this won't work for the first newsegment event though ... */
- if (gst_flac_dec_convert_src (dec->srcpad, GST_FORMAT_TIME, seg.start,
- &dformat, &start) && start != -1 &&
- gst_flac_dec_convert_src (dec->srcpad, GST_FORMAT_TIME, seg.stop,
- &dformat, &stop) && stop != -1) {
-
- seg.start = start;
- seg.stop = stop;
- dec->segment = seg;
-
- GST_DEBUG_OBJECT (dec, "segment %" GST_SEGMENT_FORMAT, &dec->segment);
- } else {
- GST_WARNING_OBJECT (dec, "couldn't convert time => samples");
- }
- } else if (seg.format == GST_FORMAT_BYTES || TRUE) {
- /* FIXME: error out or post warning, we require parsed input */
- gst_event_unref (event);
- res = FALSE;
- }
- break;
+ if (available > 0) {
+ GST_INFO_OBJECT (dec, "draining, %u bytes left in adapter", available);
+ FLAC__stream_decoder_process_until_end_of_stream (dec->decoder);
}
- case GST_EVENT_EOS:{
- GST_LOG_OBJECT (dec, "EOS, with %u bytes available in adapter",
- gst_adapter_available (dec->adapter));
- if (dec->init == FALSE) {
- if (gst_adapter_available (dec->adapter) > 0) {
- FLAC__stream_decoder_process_until_end_of_stream (dec->decoder);
- }
- FLAC__stream_decoder_flush (dec->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;
+ FLAC__stream_decoder_flush (dec->decoder);
+ gst_adapter_clear (dec->adapter);
}
static gboolean
@@ -905,39 +781,29 @@ gst_flac_dec_chain_parse_headers (GstFlacDec * dec)
}
static GstFlowReturn
-gst_flac_dec_chain (GstPad * pad, GstBuffer * buf)
+gst_flac_dec_handle_frame (GstAudioDecoder * audio_dec, GstBuffer * buf)
{
- FLAC__StreamDecoderInitStatus s;
GstFlacDec *dec;
gboolean got_audio_frame;
- dec = GST_FLAC_DEC (GST_PAD_PARENT (pad));
-
- GST_LOG_OBJECT (dec,
- "buffer with ts=%" GST_TIME_FORMAT ", offset=%" G_GINT64_FORMAT
- ", end_offset=%" G_GINT64_FORMAT ", size=%" G_GSIZE_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_OFFSET (buf),
- GST_BUFFER_OFFSET_END (buf), gst_buffer_get_size (buf));
-
- if (dec->init) {
- GST_DEBUG_OBJECT (dec, "initializing decoder");
- s = FLAC__stream_decoder_init_stream (dec->decoder,
- gst_flac_dec_read_stream, NULL, NULL, NULL, NULL,
- gst_flac_dec_write_stream, gst_flac_dec_metadata_cb,
- gst_flac_dec_error_cb, dec);
- if (s != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
- 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;
- } else 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->decoder);
+ dec = GST_FLAC_DEC (audio_dec);
+
+ /* drain remaining data? */
+ if (G_UNLIKELY (buf == NULL)) {
+ gst_flac_dec_flush (audio_dec, FALSE);
+ return GST_FLOW_OK;
+ }
+
+ GST_LOG_OBJECT (dec, "frame: ts %" GST_TIME_FORMAT ", flags 0x%04x, %u bytes",
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_FLAGS (buf),
+ gst_buffer_get_size (buf));
+
+ if (G_UNLIKELY (!dec->got_headers)) {
+// FIXME
}
/* FIXME: should always be framed */
+ dec->framed = TRUE;
if (dec->framed) {
gint64 unused;
guint8 *data;
@@ -947,22 +813,11 @@ gst_flac_dec_chain (GstPad * pad, GstBuffer * buf)
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
got_audio_frame = gst_flac_dec_scan_got_frame (dec, data, size, &unused);
gst_buffer_unmap (buf, data, size);
-
- if (G_LIKELY (got_audio_frame)) {
- GstFormat dformat = GST_FORMAT_DEFAULT; /* FIXME: remove var */
- gint64 position;
-
- /* upstream (e.g. demuxer) presents us time,
- * convert to default samples */
- gst_flac_dec_convert_src (dec->srcpad, GST_FORMAT_TIME,
- GST_BUFFER_TIMESTAMP (buf), &dformat, &position);
- dec->segment.position = position;
- }
} else {
got_audio_frame = TRUE;
}
- gst_adapter_push (dec->adapter, buf);
+ gst_adapter_push (dec->adapter, gst_buffer_ref (buf));
buf = NULL;
dec->last_flow = GST_FLOW_OK;
@@ -1029,358 +884,3 @@ out:
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)
-{
- GstFlacDec *flacdec = GST_FLAC_DEC (GST_PAD_PARENT (pad));
- gboolean res = TRUE;
- guint bytes_per_sample;
- guint scale = 1;
-
- if (flacdec->width == 0 || flacdec->channels == 0 ||
- flacdec->sample_rate == 0) {
- /* no frame decoded yet */
- GST_DEBUG_OBJECT (flacdec, "cannot convert: not set up yet");
- return FALSE;
- }
-
- bytes_per_sample = flacdec->channels * (flacdec->width / 8);
-
- switch (src_format) {
- case GST_FORMAT_BYTES:{
- switch (*dest_format) {
- case GST_FORMAT_DEFAULT:
- *dest_value =
- gst_util_uint64_scale_int (src_value, 1, bytes_per_sample);
- break;
- case GST_FORMAT_TIME:
- {
- gint byterate = bytes_per_sample * flacdec->sample_rate;
-
- *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
- byterate);
- break;
- }
- default:
- res = FALSE;
- }
- break;
- }
- case GST_FORMAT_DEFAULT:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- *dest_value = src_value * bytes_per_sample;
- break;
- case GST_FORMAT_TIME:
- *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
- flacdec->sample_rate);
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_TIME:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- scale = bytes_per_sample;
- case GST_FORMAT_DEFAULT:
- *dest_value = gst_util_uint64_scale_int_round (src_value,
- scale * flacdec->sample_rate, GST_SECOND);
- break;
- default:
- res = FALSE;
- }
- break;
- default:
- res = FALSE;
- }
- return res;
-}
-
-static const GstQueryType *
-gst_flac_dec_get_src_query_types (GstPad * pad)
-{
- static const GstQueryType types[] = {
- GST_QUERY_POSITION,
- GST_QUERY_DURATION,
- GST_QUERY_CONVERT,
- GST_QUERY_SEEKING,
- 0,
- };
-
- return types;
-}
-
-static gboolean
-gst_flac_dec_src_query (GstPad * pad, GstQuery * query)
-{
- GstFlacDec *flacdec;
- gboolean res = TRUE;
- GstPad *peer;
-
- flacdec = GST_FLAC_DEC (gst_pad_get_parent (pad));
- peer = gst_pad_get_peer (flacdec->sinkpad);
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:{
- GstFormat fmt;
- gint64 pos;
-
- 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.position, &fmt, &pos)) {
- GST_DEBUG_OBJECT (flacdec, "failed to convert position into %s "
- "format", gst_format_get_name (fmt));
- res = FALSE;
- goto done;
- }
- } else {
- pos = flacdec->segment.position;
- }
-
- gst_query_set_position (query, fmt, pos);
-
- GST_DEBUG_OBJECT (flacdec, "returning position %" G_GUINT64_FORMAT
- " (format: %s)", pos, gst_format_get_name (fmt));
-
- res = TRUE;
- break;
- }
-
- case GST_QUERY_DURATION:{
- GstFormat fmt;
- gint64 len;
-
- gst_query_parse_duration (query, &fmt, NULL);
-
- /* try any demuxers or parsers before us first */
- if ((fmt == GST_FORMAT_TIME || fmt == GST_FORMAT_DEFAULT) &&
- peer != NULL && gst_pad_query (peer, query)) {
- gst_query_parse_duration (query, NULL, &len);
- GST_DEBUG_OBJECT (flacdec, "peer returned duration %" GST_TIME_FORMAT,
- GST_TIME_ARGS (len));
- res = TRUE;
- goto done;
- }
-
- if (flacdec->segment.duration == 0 || flacdec->segment.duration == -1) {
- GST_DEBUG_OBJECT (flacdec, "duration not known yet");
- res = FALSE;
- goto done;
- }
-
- /* convert total number of samples to request format */
- if (fmt != GST_FORMAT_DEFAULT) {
- if (!gst_flac_dec_convert_src (flacdec->srcpad, GST_FORMAT_DEFAULT,
- flacdec->segment.duration, &fmt, &len)) {
- GST_DEBUG_OBJECT (flacdec, "failed to convert duration into %s "
- "format", gst_format_get_name (fmt));
- res = FALSE;
- goto done;
- }
- } else {
- len = flacdec->segment.duration;
- }
-
- gst_query_set_duration (query, fmt, len);
-
- GST_DEBUG_OBJECT (flacdec, "returning duration %" G_GUINT64_FORMAT
- " (format: %s)", len, gst_format_get_name (fmt));
-
- res = TRUE;
- break;
- }
-
- 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_src (pad, src_fmt, src_val, &dest_fmt,
- &dest_val);
-
- if (res) {
- gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
- }
-
- break;
- }
- default:{
- res = gst_pad_query_default (pad, query);
- break;
- }
- }
-
-done:
-
- if (peer)
- gst_object_unref (peer);
-
- gst_object_unref (flacdec);
-
- return res;
-}
-
-static gboolean
-gst_flac_dec_sink_activate (GstPad * sinkpad)
-{
- GST_DEBUG_OBJECT (sinkpad, "activating push");
- 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));
-
- if (active) {
- gst_flac_dec_setup_decoder (dec);
- dec->got_headers = FALSE;
- }
- return TRUE;
-}
-
-static GstStateChangeReturn
-gst_flac_dec_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstFlacDec *flacdec = GST_FLAC_DEC (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- flacdec->channels = 0;
- flacdec->depth = 0;
- flacdec->width = 0;
- flacdec->sample_rate = 0;
- gst_segment_init (&flacdec->segment, GST_FORMAT_DEFAULT);
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
- if (ret == GST_STATE_CHANGE_FAILURE)
- return ret;
-
- 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;
- }
-
- return ret;
-}
diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h
index 402c3c05e..8c2ec0e9f 100644
--- a/ext/flac/gstflacdec.h
+++ b/ext/flac/gstflacdec.h
@@ -1,5 +1,6 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2011> Tim-Philipp Müller <tim centricular net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,9 +22,8 @@
#ifndef __GST_FLAC_DEC_H__
#define __GST_FLAC_DEC_H__
-
#include <gst/gst.h>
-#include <gst/base/gstadapter.h>
+#include <gst/audio/gstaudiodecoder.h>
#include <FLAC/all.h>
@@ -39,27 +39,19 @@ typedef struct _GstFlacDec GstFlacDec;
typedef struct _GstFlacDecClass GstFlacDecClass;
struct _GstFlacDec {
- GstElement element;
-
- /* < private > */
+ GstAudioDecoder audiodecoder;
+ /*< private >*/
FLAC__StreamDecoder *decoder;
GstAdapter *adapter;
- gboolean framed;
-
- gboolean got_headers; /* if we've parsed the headers (unframed push mode only) */
+ gboolean framed; // FIXME
- GstPad *sinkpad;
- GstPad *srcpad;
+ gboolean got_headers; /* if we've parsed the headers */
- gboolean init;
-
- GstSegment segment; /* the currently configured segment, in
- * samples/audio frames (DEFAULT format) */
GstTagList *tags;
- GstFlowReturn last_flow; /* the last flow return received from either
- * gst_pad_push or gst_pad_buffer_alloc */
+ GstFlowReturn last_flow; /* to marshal flow return from finis_frame to
+ * handle_frame via flac callbacks */
gint channels;
gint depth;
@@ -69,12 +61,10 @@ struct _GstFlacDec {
/* from the stream info, needed for scanning */
guint16 min_blocksize;
guint16 max_blocksize;
-
- gint64 cur_granulepos; /* only used in framed mode (flac-in-ogg) */
};
struct _GstFlacDecClass {
- GstElementClass parent_class;
+ GstAudioDecoderClass audiodecoder;
};
GType gst_flac_dec_get_type (void);