diff options
-rw-r--r-- | ChangeLog | 11 | ||||
m--------- | common | 0 | ||||
-rw-r--r-- | gst/wavparse/gstwavparse.c | 94 | ||||
-rw-r--r-- | gst/wavparse/gstwavparse.h | 11 |
4 files changed, 90 insertions, 26 deletions
@@ -1,3 +1,14 @@ +2006-03-23 Tim-Philipp Müller <tim at centricular dot net> + + * 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). + 2006-03-22 Jan Schmidt <thaytan@mad.scientist.com> * gst/apetag/gsttagdemux.c: (gst_tag_demux_chain): diff --git a/common b/common -Subproject f1c7bfd24d0fcc4e5113ce3b96b1fac83a9ec56 +Subproject 658b51189850df022f032a4310c4ad477a76465 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; |