gst/matroska/: Add Real[Audio|Video] support to Matroska containers.
authorEdward Hervey <bilboed@bilboed.com>
Mon, 25 Aug 2008 14:15:43 +0000 (14:15 +0000)
committerEdward Hervey <bilboed@bilboed.com>
Mon, 25 Aug 2008 14:15:43 +0000 (14:15 +0000)
Original commit message from CVS:
* gst/matroska/matroska-demux.c: (gst_matroska_demux_send_event),
(gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps):
* gst/matroska/matroska-mux.c:
(gst_matroska_mux_video_pad_setcaps),
(gst_matroska_mux_audio_pad_setcaps), (gst_matroska_mux_finish):
Add Real[Audio|Video] support to Matroska containers.
It works fine for:
* decoding real audio/video streams contained in mkv
* 'transmuxing' real (.rm) files into .mkv files
It will not work though for encoding real[audio/video] streams that
don't contain the 'mdpr_data' extra data on the caps.
The reason why this will not work is because I never intended to
duplicate virtually all the 'mdpr' block creation into mkvmux.
Fixes #536067

ChangeLog
gst/matroska/matroska-demux.c
gst/matroska/matroska-mux.c

index 448dc19..b525b97 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2008-08-25  Edward Hervey  <edward.hervey@collabora.co.uk>
+
+       * gst/matroska/matroska-demux.c: (gst_matroska_demux_send_event),
+       (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps):
+       * gst/matroska/matroska-mux.c:
+       (gst_matroska_mux_video_pad_setcaps),
+       (gst_matroska_mux_audio_pad_setcaps), (gst_matroska_mux_finish):
+       Add Real[Audio|Video] support to Matroska containers.
+       It works fine for:
+       * decoding real audio/video streams contained in mkv
+       * 'transmuxing' real (.rm) files into .mkv files
+       It will not work though for encoding real[audio/video] streams that
+       don't contain the 'mdpr_data' extra data on the caps.
+       The reason why this will not work is because I never intended to
+       duplicate virtually all the 'mdpr' block creation into mkvmux.
+       Fixes #536067
+
 2008-08-25  Wim Taymans  <wim.taymans@collabora.co.uk>
 
        * gst/law/alaw-encode.c: (gst_alaw_enc_init), (gst_alaw_enc_chain):
index 09c4b54..56b08e1 100644 (file)
@@ -1995,6 +1995,8 @@ gst_matroska_demux_send_event (GstMatroskaDemux * demux, GstEvent * event)
     gst_pad_push_event (stream->pad, event);
 
     if (stream->pending_tags) {
+      GST_DEBUG_OBJECT (demux, "Sending pending_tags %p for pad %s:%s",
+          stream->pending_tags, GST_DEBUG_PAD_NAME (stream->pad));
       gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
           stream->pending_tags);
       stream->pending_tags = NULL;
@@ -5091,6 +5093,29 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *
 
     caps = gst_caps_new_simple ("video/x-pn-realvideo",
         "rmversion", G_TYPE_INT, rmversion, NULL);
+    GST_DEBUG ("data:%p, size:0x%x", data, size);
+    /* We need to extract the extradata ! */
+    if (data && (size >= 0x22)) {
+      GstBuffer *priv;
+      guint rformat;
+      guint subformat;
+
+      gst_util_dump_mem (data, size);
+      gst_util_dump_mem (data + 0x1a, size - 0x1a);
+
+      subformat = GST_READ_UINT32_BE (data + 0x1a);
+      rformat = GST_READ_UINT32_BE (data + 0x1e);
+
+      priv = gst_buffer_new_and_alloc (size - 0x1a);
+
+      memcpy (GST_BUFFER_DATA (priv), data + 0x1a, size - 0x1a);
+      gst_caps_set_simple (caps,
+          "codec_data", GST_TYPE_BUFFER, priv,
+          "format", G_TYPE_INT, rformat,
+          "subformat", G_TYPE_INT, subformat, NULL);
+      gst_buffer_unref (priv);
+
+    }
     *codec_name = g_strdup_printf ("RealVideo %d.0", rmversion);
   } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_THEORA)) {
     caps = gst_caps_new_simple ("video/x-theora", NULL);
@@ -5425,8 +5450,47 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
       raversion = 8;
     else
       raversion = 2;
+
     caps = gst_caps_new_simple ("audio/x-pn-realaudio",
         "raversion", G_TYPE_INT, raversion, NULL);
+    /* Extract extra information from caps, mapping varies based on codec */
+    if (data && (size >= 0x50)) {
+      GstBuffer *priv;
+      guint flavor;
+      guint packet_size;
+      guint height;
+      guint leaf_size;
+      guint sample_width;
+      guint extra_data_size;
+
+      GST_ERROR ("real audio raversion:%d", raversion);
+      gst_util_dump_mem (data, size);
+      if (raversion == 8) {
+        /* COOK */
+        flavor = GST_READ_UINT16_BE (data + 22);
+        packet_size = GST_READ_UINT32_BE (data + 24);
+        height = GST_READ_UINT16_BE (data + 40);
+        leaf_size = GST_READ_UINT16_BE (data + 44);
+        sample_width = GST_READ_UINT16_BE (data + 58);
+        extra_data_size = GST_READ_UINT32_BE (data + 74);
+
+        GST_ERROR
+            ("flavor:%d, packet_size:%d, height:%d, leaf_size:%d, sample_width:%d, extra_data_size:%d",
+            flavor, packet_size, height, leaf_size, sample_width,
+            extra_data_size);
+        gst_caps_set_simple (caps, "flavor", G_TYPE_INT, flavor, "packet_size",
+            G_TYPE_INT, packet_size, "height", G_TYPE_INT, height, "leaf_size",
+            G_TYPE_INT, leaf_size, "width", G_TYPE_INT, sample_width, NULL);
+
+        if ((size - 78) >= extra_data_size) {
+          priv = gst_buffer_new_and_alloc (extra_data_size);
+          memcpy (GST_BUFFER_DATA (priv), data + 78, extra_data_size);
+          gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, priv, NULL);
+          gst_buffer_unref (priv);
+        }
+      }
+    }
+
     *codec_name = g_strdup_printf ("RealAudio %d.0", raversion);
   } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_REAL_SIPR)) {
     caps = gst_caps_new_simple ("audio/x-sipro", NULL);
index 6138bcb..dfe51a0 100644 (file)
@@ -91,6 +91,9 @@ static GstStaticPadTemplate videosink_templ =
         "video/x-theora; "
         "video/x-dirac, "
         COMMON_VIDEO_CAPS "; "
+        "video/x-pn-realvideo, "
+        "rmversion = (int) [1, 4], "
+        COMMON_VIDEO_CAPS "; "
         "video/x-raw-yuv, "
         "format = (fourcc) { YUY2, I420, YV12, UYVY, AYUV }, "
         COMMON_VIDEO_CAPS)
@@ -149,7 +152,9 @@ static GstStaticPadTemplate audiosink_templ =
         COMMON_AUDIO_CAPS ";"
         "audio/x-tta, "
         "width = (int) { 8, 16, 24 }, "
-        "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]")
+        "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]; "
+        "audio/x-pn-realaudio, "
+        "raversion = (int) { 1, 2, 8 }, " COMMON_AUDIO_CAPS ";")
     );
 
 static GstStaticPadTemplate subtitlesink_templ =
@@ -752,6 +757,45 @@ skip_details:
     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3);
 
     return TRUE;
+  } else if (!strcmp (mimetype, "video/x-pn-realvideo")) {
+    gint rmversion;
+    const GValue *mdpr_data;
+
+    gst_structure_get_int (structure, "rmversion", &rmversion);
+    switch (rmversion) {
+      case 1:
+        context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO1);
+        break;
+      case 2:
+        context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2);
+        break;
+      case 3:
+        context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3);
+        break;
+      case 4:
+        context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4);
+        break;
+      default:
+        return FALSE;
+    }
+
+    mdpr_data = gst_structure_get_value (structure, "mdpr_data");
+    if (mdpr_data != NULL) {
+      guint8 *priv_data = NULL;
+      guint priv_data_size = 0;
+
+      GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
+
+      priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
+      priv_data = g_malloc0 (priv_data_size);
+
+      memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
+
+      context->codec_priv = priv_data;
+      context->codec_priv_size = priv_data_size;
+    }
+
+    return TRUE;
   }
 
   return FALSE;
@@ -1204,6 +1248,42 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
     context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_TTA);
 
     return TRUE;
+  } else if (!strcmp (mimetype, "audio/x-pn-realaudio")) {
+    gint raversion;
+    const GValue *mdpr_data;
+
+    gst_structure_get_int (structure, "raversion", &raversion);
+    switch (raversion) {
+      case 1:
+        context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_14_4);
+        break;
+      case 2:
+        context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_28_8);
+        break;
+      case 8:
+        context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_REAL_COOK);
+        break;
+      default:
+        return FALSE;
+    }
+
+    mdpr_data = gst_structure_get_value (structure, "mdpr_data");
+    if (mdpr_data != NULL) {
+      guint8 *priv_data = NULL;
+      guint priv_data_size = 0;
+
+      GstBuffer *codec_data_buf = g_value_peek_pointer (mdpr_data);
+
+      priv_data_size = GST_BUFFER_SIZE (codec_data_buf);
+      priv_data = g_malloc0 (priv_data_size);
+
+      memcpy (priv_data, GST_BUFFER_DATA (codec_data_buf), priv_data_size);
+
+      context->codec_priv = priv_data;
+      context->codec_priv_size = priv_data_size;
+    }
+
+    return TRUE;
   }
 
   return FALSE;
@@ -1687,6 +1767,8 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
   if (tags != NULL) {
     guint64 master_tags, master_tag;
 
+    GST_DEBUG ("Writing tags");
+
     /* TODO: maybe limit via the TARGETS id by looking at the source pad */
     mux->tags_pos = ebml->pos;
     master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);