From 92361863e6f4fabc919d9eeeac2370f0b859908a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 9 Oct 2011 16:18:09 +0100 Subject: [PATCH] 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. --- ext/flac/gstflacdec.c | 728 ++++++++------------------------------------------ ext/flac/gstflacdec.h | 28 +- 2 files changed, 123 insertions(+), 633 deletions(-) diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c index e35672a..7ae1754 100644 --- a/ext/flac/gstflacdec.c +++ b/ext/flac/gstflacdec.c @@ -45,8 +45,6 @@ #include "gstflacdec.h" #include -#include -#include #include #include @@ -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 "); + "Codec/Decoder/Audio", "Decodes FLAC lossless audio streams", + "Tim-Philipp Müller , " + "Wim Taymans "); } 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 402c3c0..8c2ec0e 100644 --- a/ext/flac/gstflacdec.h +++ b/ext/flac/gstflacdec.h @@ -1,5 +1,6 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2011> Tim-Philipp Müller * * 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 -#include +#include #include @@ -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); -- 2.7.4