From a0fa3b2917891bc36e3c186bc2d5389233571331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 4 Sep 2006 15:06:25 +0000 Subject: [PATCH] gst/matroska/: not perfect yet though, needs some tweaking in flacdec; also, seeking could be better. Original commit message from CVS: * gst/matroska/matroska-demux.c: (gst_matroska_demux_push_hdr_buf), (gst_matroska_demux_push_flac_codec_priv_data), (gst_matroska_demux_push_xiph_codec_priv_data), (gst_matroska_demux_parse_blockgroup_or_simpleblock), (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps): * gst/matroska/matroska-ids.h: Add basic FLAC support (#311586), not perfect yet though, needs some tweaking in flacdec; also, seeking could be better. Do better bounds checking when deserialising vorbis stream headers to make sure we don't read beyond the end of the buffer on bad input. --- ChangeLog | 13 ++++ gst/matroska/matroska-demux.c | 118 +++++++++++++++++++++++++++------- gst/matroska/matroska-ids.h | 6 ++ 3 files changed, 115 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index debc6818b3..4780d75754 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2006-09-04 Tim-Philipp Müller + + * gst/matroska/matroska-demux.c: (gst_matroska_demux_push_hdr_buf), + (gst_matroska_demux_push_flac_codec_priv_data), + (gst_matroska_demux_push_xiph_codec_priv_data), + (gst_matroska_demux_parse_blockgroup_or_simpleblock), + (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps): + * gst/matroska/matroska-ids.h: + Add basic FLAC support (#311586), not perfect yet though, needs some + tweaking in flacdec; also, seeking could be better. + Do better bounds checking when deserialising vorbis stream headers + to make sure we don't read beyond the end of the buffer on bad input. + 2006-09-04 Wim Taymans Patch by: Alessandro Decina diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 91556638f7..3d6208deb5 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -2040,41 +2040,103 @@ gst_matroska_demux_sync_streams (GstMatroskaDemux * demux) } } +static gboolean +gst_matroska_demux_push_hdr_buf (GstMatroskaDemux * demux, + GstMatroskaTrackContext * stream, guint8 * data, guint len) +{ + GstFlowReturn flow; + GstBuffer *header_buf = NULL; + + flow = gst_pad_alloc_buffer_and_set_caps (stream->pad, + GST_BUFFER_OFFSET_NONE, len, stream->caps, &header_buf); + + if (flow == GST_FLOW_OK) { + memcpy (GST_BUFFER_DATA (header_buf), data, len); + flow = gst_pad_push (stream->pad, header_buf); + } + + if (flow != GST_FLOW_OK && flow != GST_FLOW_NOT_LINKED) + return FALSE; + + return TRUE; +} + +static gboolean +gst_matroska_demux_push_flac_codec_priv_data (GstMatroskaDemux * demux, + GstMatroskaTrackContext * stream) +{ + guint8 *pdata; + guint off, len; + + GST_LOG_OBJECT (demux, "priv data size = %u", stream->codec_priv_size); + + pdata = (guint8 *) stream->codec_priv; + + /* need at least 'fLaC' marker + STREAMINFO metadata block */ + if (stream->codec_priv_size < ((4) + (4 + 34))) { + GST_WARNING_OBJECT (demux, "not enough codec priv data for flac headers"); + return FALSE; + } + + if (memcmp (pdata, "fLaC", 4) != 0) { + GST_WARNING_OBJECT (demux, "no flac marker at start of stream headers"); + return FALSE; + } + + if (!gst_matroska_demux_push_hdr_buf (demux, stream, pdata, 4)) + return FALSE; + + off = 4; /* skip fLaC marker */ + while (off < stream->codec_priv_size) { + len = GST_READ_UINT8 (pdata + off + 1) << 16; + len |= GST_READ_UINT8 (pdata + off + 2) << 8; + len |= GST_READ_UINT8 (pdata + off + 3); + + GST_DEBUG_OBJECT (demux, "header packet: len=%u bytes, flags=0x%02x", + len, (guint) pdata[off]); + + if (!gst_matroska_demux_push_hdr_buf (demux, stream, pdata + off, len)) + return FALSE; + + off += 4 + len; + } + + return TRUE; +} + static gboolean gst_matroska_demux_push_xiph_codec_priv_data (GstMatroskaDemux * demux, GstMatroskaTrackContext * stream) { - GstFlowReturn ret; - GstBuffer *priv; - guint32 offset, length; - guchar *p; - gint i; + guint8 *p = (guint8 *) stream->codec_priv; + gint i, offset, length, num_packets; /* start of the stream and vorbis audio or theora video, need to * send the codec_priv data as first three packets */ - p = (guchar *) stream->codec_priv; - offset = 3; + num_packets = p[0] + 1; + GST_DEBUG_OBJECT (demux, "%u stream headers, total length=%u bytes", + (guint) num_packets, stream->codec_priv_size); - for (i = 0; i < 2; i++) { + offset = num_packets; /* offset to data of first packet */ + + for (i = 0; i < num_packets - 1; i++) { length = p[i + 1]; - if (gst_pad_alloc_buffer_and_set_caps (stream->pad, GST_BUFFER_OFFSET_NONE, - length, stream->caps, &priv) == GST_FLOW_OK) { - memcpy (GST_BUFFER_DATA (priv), &p[offset], length); - ret = gst_pad_push (stream->pad, priv); - if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) - return FALSE; - } + GST_DEBUG_OBJECT (demux, "buffer %d: length=%u bytes", i, (guint) length); + if (offset + length > stream->codec_priv_size) + return FALSE; + + if (!gst_matroska_demux_push_hdr_buf (demux, stream, p + offset, length)) + return FALSE; + offset += length; } + length = stream->codec_priv_size - offset; - if (gst_pad_alloc_buffer_and_set_caps (stream->pad, GST_BUFFER_OFFSET_NONE, - length, stream->caps, &priv) == GST_FLOW_OK) { - memcpy (GST_BUFFER_DATA (priv), &p[offset], length); - ret = gst_pad_push (stream->pad, priv); - if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) - return FALSE; - } + GST_DEBUG_OBJECT (demux, "buffer %d: length=%u bytes", i, (guint) length); + if (!gst_matroska_demux_push_hdr_buf (demux, stream, p + offset, length)) + return FALSE; + return TRUE; } @@ -2373,6 +2435,13 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux, stream->send_xiph_headers = FALSE; } + if (stream->send_flac_headers) { + if (!gst_matroska_demux_push_flac_codec_priv_data (demux, stream)) { + got_error = TRUE; + } + stream->send_flac_headers = FALSE; + } + if (got_error) break; @@ -3044,6 +3113,7 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * g_assert (codec_name != NULL); context->send_xiph_headers = FALSE; + context->send_flac_headers = FALSE; if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC)) { gst_riff_strf_vids *vids = NULL; @@ -3325,6 +3395,7 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * g_assert (codec_name != NULL); context->send_xiph_headers = FALSE; + context->send_flac_headers = FALSE; if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1) || !strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2) || @@ -3379,6 +3450,9 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * caps = gst_caps_new_simple ("audio/x-vorbis", NULL); context->send_xiph_headers = TRUE; /* vorbis decoder does tags */ + } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_FLAC)) { + caps = gst_caps_new_simple ("audio/x-flac", NULL); + context->send_flac_headers = TRUE; } else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_ACM)) { gst_riff_strf_auds *auds = NULL; diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h index cfc7b80d33..0c05974bd8 100644 --- a/gst/matroska/matroska-ids.h +++ b/gst/matroska/matroska-ids.h @@ -156,6 +156,7 @@ #define GST_MATROSKA_CODEC_ID_AUDIO_AC3 "A_AC3" #define GST_MATROSKA_CODEC_ID_AUDIO_DTS "A_DTS" #define GST_MATROSKA_CODEC_ID_AUDIO_VORBIS "A_VORBIS" +#define GST_MATROSKA_CODEC_ID_AUDIO_FLAC "A_FLAC" #define GST_MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" #define GST_MATROSKA_CODEC_ID_AUDIO_MPEG2 "A_AAC/MPEG2/" #define GST_MATROSKA_CODEC_ID_AUDIO_MPEG4 "A_AAC/MPEG4/" @@ -254,6 +255,11 @@ typedef struct _GstMatroskaTrackContext { * for time == 0 is not enough to detect that. Used by demuxer */ gboolean send_xiph_headers; + /* Special flag for Flac, for which we need to reconstruct the header + * buffer from the codec_priv data before sending any data, and just + * testing for time == 0 is not enough to detect that. Used by demuxer */ + gboolean send_flac_headers; + /* Special counter for muxer to skip the first N vorbis/theora headers - * they are put into codec private data, not muxed into the stream */ guint xiph_headers_to_skip;