diff --git a/ChangeLog b/ChangeLog index 448dc191ec..b525b97c05 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2008-08-25 Edward Hervey + + * 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 * gst/law/alaw-encode.c: (gst_alaw_enc_init), (gst_alaw_enc_chain): diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 09c4b5491e..56b08e149b 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -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); diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index 6138bcb44d..dfe51a07ec 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -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 = @@ -751,6 +756,45 @@ skip_details: } else if (!strcmp (mimetype, "video/x-msmpeg")) { 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; } @@ -1203,6 +1247,42 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps) audiocontext->bitdepth = width; 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; } @@ -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);