mssdemux: fix setting codec_data when using WaveFormatEx
authorAntonio Ospite <ospite@studenti.unina.it>
Thu, 31 Oct 2013 16:16:14 +0000 (17:16 +0100)
committerThiago Santos <ts.santos@sisa.samsung.com>
Wed, 27 Nov 2013 12:26:36 +0000 (09:26 -0300)
When using WaveFormatEx the actual codec private data is at the end of
the wav header structure, after the cbSize field, see for example the
notes at http://wiki.multimedia.cx/index.php?title=WAVEFORMATEX

The previous code was erroneously passing the whole WAVEFORMATEX
structure as codec_data.

The smoothstreaming specifications[1,2,3] always mention WAVEFORMATEX
and never smaller structures like WAVEFORMAT or PCMWAVEFORMAT, so the
buffer can assumed to be at least 18 bytes and always consuming the wav
header gives the (possibly empty) codec private data.

[1] http://web.archive.org/web/20120907004742/http://www.iis.net/community/files/media/smoothspecs/%5BMS-SMTH%5D.pdf
[2] http://download.microsoft.com/download/B/0/B/B0B199DB-41E6-400F-90CD-C350D0C14A53/%5BMS-SSTR%5D.pdf
[3] http://download.microsoft.com/download/9/5/E/95EF66AF-9026-4BB0-A41D-A4F81802D92C/%5BMS-SSTR%5D.pdf

https://bugzilla.gnome.org/show_bug.cgi?id=699924

ext/smoothstreaming/gstmssmanifest.c

index e882437..85f3da2 100644 (file)
@@ -597,23 +597,34 @@ _gst_mss_stream_audio_caps_from_qualitylevel_xml (GstMssStreamQuality * q)
     block_align = (int) g_ascii_strtoull (block_align_str, NULL, 10);
 
   if (!codec_data) {
-    GstMapInfo mapinfo;
+    gint codec_data_len;
     codec_data_str = (gchar *) xmlGetProp (node, (xmlChar *) "WaveFormatEx");
-    if (codec_data_str && strlen (codec_data_str)) {
+    codec_data_len = strlen (codec_data_str) / 2;
+
+    /* a WAVEFORMATEX structure is 18 bytes */
+    if (codec_data_str && codec_data_len >= 18) {
+      GstMapInfo mapinfo;
       codec_data = gst_buffer_from_hex_string ((gchar *) codec_data_str);
 
-      /* since this is a waveformatex, try to get the block_align and rate */
+      /* since this is a WAVEFORMATEX, try to get the block_align and rate */
       gst_buffer_map (codec_data, &mapinfo, GST_MAP_READ);
-      if (mapinfo.size >= 14) {
-        if (!channels_str) {
-          channels = GST_READ_UINT16_LE (mapinfo.data + 2);
-        }
-        if (!rate_str) {
-          rate = GST_READ_UINT32_LE (mapinfo.data + 4);
-        }
+      if (!channels_str) {
+        channels = GST_READ_UINT16_LE (mapinfo.data + 2);
+      }
+      if (!rate_str) {
+        rate = GST_READ_UINT32_LE (mapinfo.data + 4);
+      }
+      if (!block_align) {
         block_align = GST_READ_UINT16_LE (mapinfo.data + 12);
       }
       gst_buffer_unmap (codec_data, &mapinfo);
+
+      /* Consume all the WAVEFORMATEX structure, and pass only the rest of
+       * the data as the codec private data */
+      gst_buffer_resize (codec_data, 18, -1);
+    } else {
+      GST_WARNING ("Dropping WaveFormatEx: data is %d bytes, "
+          "but at least 18 bytes are expected", codec_data_len);
     }
   }