summaryrefslogtreecommitdiffstats
path: root/gst/wavparse
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim@centricular.net>2006-03-23 15:36:27 +0000
committerTim-Philipp Müller <tim@centricular.net>2006-03-23 15:36:27 +0000
commitabb13bdd249c9f6eaa9f6ec8b03f62381625ea49 (patch)
treef5f916bcb646c58d37546d34da173f6fcf360665 /gst/wavparse
parente035ba08376aba93a469e254e394ef2aecb4d043 (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.c94
-rw-r--r--gst/wavparse/gstwavparse.h11
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;