diff options
author | Tim-Philipp Müller <tim@centricular.net> | 2006-03-23 15:36:27 +0000 |
---|---|---|
committer | Tim-Philipp Müller <tim@centricular.net> | 2006-03-23 15:36:27 +0000 |
commit | abb13bdd249c9f6eaa9f6ec8b03f62381625ea49 (patch) | |
tree | f5f916bcb646c58d37546d34da173f6fcf360665 /gst/wavparse | |
parent | e035ba08376aba93a469e254e394ef2aecb4d043 (diff) |
gst/wavparse/gstwavparse.*: Delay source pad creation until we have the first chunk of media data, so the we can exam...
Original commit message from CVS:
* gst/wavparse/gstwavparse.c: (gst_wavparse_perform_seek),
(gst_wavparse_stream_headers), (gst_wavparse_add_src_pad),
(gst_wavparse_stream_data), (gst_wavparse_loop):
* gst/wavparse/gstwavparse.h:
Delay source pad creation until we have the first chunk of
media data, so the we can examine the data and adjust the
caps accordingly if required. This makes playback of .wav
files with DTS-declared-as-PCM content work (#313266).
Diffstat (limited to 'gst/wavparse')
-rw-r--r-- | gst/wavparse/gstwavparse.c | 94 | ||||
-rw-r--r-- | gst/wavparse/gstwavparse.h | 11 |
2 files changed, 79 insertions, 26 deletions
diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c index 7e57ed3b..fcb773eb 100644 --- a/gst/wavparse/gstwavparse.c +++ b/gst/wavparse/gstwavparse.c @@ -119,7 +119,7 @@ static GstStaticPadTemplate src_template_factory = "block_align = (int) [ 1, 8192 ], " "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ];" "audio/x-vnd.sony.atrac3;" - "audio/x-wma, " "wmaversion = (int) [ 1, 2 ]") + "audio/x-dts;" "audio/x-wma, " "wmaversion = (int) [ 1, 2 ]") ); @@ -731,6 +731,7 @@ gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event) { gboolean res; gdouble rate; + GstEvent *newsegment; GstFormat format; GstSeekFlags flags; GstSeekType cur_type, stop_type; @@ -839,10 +840,17 @@ gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event) GST_DEBUG_OBJECT (wav, "Sending newsegment from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT, wav->segment.start, stop); - gst_pad_push_event (wav->srcpad, - gst_event_new_new_segment (FALSE, - wav->segment.rate, wav->segment.format, - wav->segment.last_stop, stop, wav->segment.time)); + newsegment = + gst_event_new_new_segment (FALSE, wav->segment.rate, + wav->segment.format, wav->segment.last_stop, stop, wav->segment.time); + + if (wav->srcpad) { + gst_pad_push_event (wav->srcpad, newsegment); + } else { + /* send later when we actually create the source pad */ + g_assert (wav->newsegment == NULL); + wav->newsegment = newsegment; + } wav->segment_running = TRUE; gst_pad_start_task (wav->sinkpad, (GstTaskFunction) gst_wavparse_loop, @@ -917,23 +925,17 @@ gst_wavparse_stream_headers (GstWavParse * wav) if (!caps) goto unknown_format; - gst_wavparse_create_sourcepad (wav); - gst_pad_set_active (wav->srcpad, TRUE); - gst_pad_set_caps (wav->srcpad, caps); - gst_caps_unref (caps); - caps = NULL; - - gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad); - gst_element_no_more_pads (GST_ELEMENT (wav)); + /* create pad later so we can sniff the first few bytes + * of the real data and correct our caps if necessary */ + gst_caps_replace (&wav->caps, caps); + gst_caps_replace (&caps, NULL); if (codec_name) { - GstTagList *tags = gst_tag_list_new (); + wav->tags = gst_tag_list_new (); - gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, + gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec_name, NULL); - gst_element_found_tags_for_pad (GST_ELEMENT (wav), wav->srcpad, tags); - g_free (codec_name); codec_name = NULL; } @@ -1092,10 +1094,46 @@ gst_wavparse_send_event (GstElement * element, GstEvent * event) return res; } +static void +gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf) +{ + GstStructure *s; + const guint8 dts_marker[] = { 0xFF, 0x1F, 0x00, 0xE8, 0xF1, 0x07 }; + + s = gst_caps_get_structure (wav->caps, 0); + if (gst_structure_has_name (s, "audio/x-raw-int") && + GST_BUFFER_SIZE (buf) > 6 && + memcmp (GST_BUFFER_DATA (buf), dts_marker, 6) == 0) { + + GST_WARNING_OBJECT (wav, "Found DTS marker in file marked as raw PCM"); + gst_caps_unref (wav->caps); + wav->caps = gst_caps_from_string ("audio/x-dts"); + + gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, + GST_TAG_AUDIO_CODEC, "dts", NULL); + } + + gst_wavparse_create_sourcepad (wav); + gst_pad_set_active (wav->srcpad, TRUE); + gst_pad_set_caps (wav->srcpad, wav->caps); + gst_caps_replace (&wav->caps, NULL); + + gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad); + gst_element_no_more_pads (GST_ELEMENT (wav)); + + gst_pad_push_event (wav->srcpad, wav->newsegment); + wav->newsegment = NULL; + + if (wav->tags) { + gst_element_found_tags_for_pad (GST_ELEMENT (wav), wav->srcpad, wav->tags); + wav->tags = NULL; + } +} + #define MAX_BUFFER_SIZE 4096 static GstFlowReturn -gst_wavparse_stream_data (GstWavParse * wav) +gst_wavparse_stream_data (GstWavParse * wav, gboolean first) { GstBuffer *buf = NULL; GstFlowReturn res = GST_FLOW_OK; @@ -1103,8 +1141,8 @@ gst_wavparse_stream_data (GstWavParse * wav) GstClockTime timestamp, next_timestamp; guint64 pos, nextpos; - GST_DEBUG_OBJECT (wav, "offset : %lld , end : %lld", wav->offset, - wav->end_offset); + GST_LOG_OBJECT (wav, "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, + wav->offset, wav->end_offset); /* Get the next n bytes and output them */ if (wav->dataleft == 0) @@ -1116,8 +1154,8 @@ gst_wavparse_stream_data (GstWavParse * wav) if (desired >= wav->blockalign && wav->blockalign > 0) desired -= (desired % wav->blockalign); - GST_DEBUG_OBJECT (wav, "Fetching %lld bytes of data from the sinkpad.", - desired); + GST_LOG_OBJECT (wav, "Fetching %" G_GINT64_FORMAT " bytes of data " + "from the sinkpad", desired); if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset, desired, &buf)) != GST_FLOW_OK) @@ -1125,6 +1163,12 @@ gst_wavparse_stream_data (GstWavParse * wav) obtained = GST_BUFFER_SIZE (buf); + /* first chunk of data? create the source pad. We do this only here so + * we can detect broken .wav files with dts disguised as raw PCM (sigh) */ + if (first) { + gst_wavparse_add_src_pad (wav, buf); + } + /* our positions */ pos = wav->offset - wav->datastart; nextpos = pos + obtained; @@ -1214,9 +1258,11 @@ gst_wavparse_loop (GstPad * pad) goto pause; wav->state = GST_WAVPARSE_DATA; - /* fall-through */ + if ((ret = gst_wavparse_stream_data (wav, TRUE)) != GST_FLOW_OK) + goto pause; + break; case GST_WAVPARSE_DATA: - if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) + if ((ret = gst_wavparse_stream_data (wav, FALSE)) != GST_FLOW_OK) goto pause; break; default: diff --git a/gst/wavparse/gstwavparse.h b/gst/wavparse/gstwavparse.h index b9203140..2d140619 100644 --- a/gst/wavparse/gstwavparse.h +++ b/gst/wavparse/gstwavparse.h @@ -33,10 +33,10 @@ G_BEGIN_DECLS #define GST_WAVPARSE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPARSE,GstWavParse)) #define GST_WAVPARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPARSE,GstWavParse)) + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPARSE,GstWavParseClass)) #define GST_IS_WAVPARSE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPARSE)) -#define GST_IS_WAVPARSE_CLASS(obj) \ +#define GST_IS_WAVPARSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPARSE)) typedef enum { @@ -59,6 +59,13 @@ struct _GstWavParse { /* pads */ GstPad *sinkpad,*srcpad; + /* for delayed source pad creation for when + * we have the first chunk of data and know + * the format for sure */ + GstCaps *caps; + GstTagList *tags; + GstEvent *newsegment; + /* WAVE decoding state */ GstWavParseState state; |