gst/wavparse/gstwavparse.*: Delay source pad creation until we have the first chunk...
authorTim-Philipp Müller <tim@centricular.net>
Thu, 23 Mar 2006 15:36:27 +0000 (15:36 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Thu, 23 Mar 2006 15:36:27 +0000 (15:36 +0000)
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).

ChangeLog
common
gst/wavparse/gstwavparse.c
gst/wavparse/gstwavparse.h

index 308ea82..c5e6a85 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
index f1c7bfd..658b511 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit f1c7bfd24d0fcc4e5113ce3b96b1fac83a9ec560
+Subproject commit 658b51189850df022f032a4310c4ad477a76465f
index 7e57ed3..fcb773e 100644 (file)
@@ -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:
index b920314..2d14061 100644 (file)
@@ -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;