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.
This commit is contained in:
Tim-Philipp Müller 2006-09-04 15:06:25 +00:00
parent fc559fff48
commit a0fa3b2917
3 changed files with 115 additions and 22 deletions

View file

@ -1,3 +1,16 @@
2006-09-04 Tim-Philipp Müller <tim at centricular dot net>
* 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 <wim@fluendo.com>
Patch by: Alessandro Decina <alessandro at nnva dot org>

View file

@ -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;

View file

@ -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;