Commit 7389cb15 authored by Edward Hervey's avatar Edward Hervey

audioparsers: fix some more parsers

parent 0b1bdcf7
......@@ -469,6 +469,7 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
int skip_size = 0;
int bitstream_type;
int sr_idx;
GstCaps *sinkcaps;
aacparse->header_type = DSPAAC_HEADER_ADIF;
aacparse->mpegversion = 4;
......@@ -531,8 +532,9 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), 512);
/* arrange for metadata and get out of the way */
gst_aac_parse_set_src_caps (aacparse,
GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (aacparse)));
sinkcaps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (aacparse));
gst_aac_parse_set_src_caps (aacparse, sinkcaps);
gst_caps_unref (sinkcaps);
/* not syncable, not easily seekable (unless we push data from start */
gst_base_parse_set_syncable (GST_BASE_PARSE_CAST (aacparse), FALSE);
......@@ -662,14 +664,18 @@ gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
if (G_UNLIKELY (rate != aacparse->sample_rate
|| channels != aacparse->channels)) {
GstCaps *sinkcaps;
aacparse->sample_rate = rate;
aacparse->channels = channels;
if (!gst_aac_parse_set_src_caps (aacparse,
GST_PAD_CAPS (GST_BASE_PARSE (aacparse)->sinkpad))) {
sinkcaps = gst_pad_get_current_caps (GST_BASE_PARSE (aacparse)->sinkpad);
if (!gst_aac_parse_set_src_caps (aacparse, sinkcaps)) {
/* If linking fails, we need to return appropriate error */
gst_caps_unref (sinkcaps);
ret = GST_FLOW_NOT_LINKED;
}
gst_caps_unref (sinkcaps);
gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
aacparse->sample_rate, 1024, 2, 2);
......
......@@ -240,18 +240,24 @@ static gboolean
gst_ac3_parse_frame_header_ac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
guint * frame_size, guint * rate, guint * chans, guint * blks, guint * sid)
{
GstBitReader bits = GST_BIT_READER_INIT_FROM_BUFFER (buf);
GstBitReader bits;
gpointer data;
gsize size;
guint8 fscod, frmsizcod, bsid, acmod, lfe_on;
gboolean ret = FALSE;
GST_LOG_OBJECT (ac3parse, "parsing ac3");
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
gst_bit_reader_init (&bits, data, size);
gst_bit_reader_skip_unchecked (&bits, 16 + 16);
fscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2);
frmsizcod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 6);
if (G_UNLIKELY (fscod == 3 || frmsizcod >= G_N_ELEMENTS (frmsizcod_table))) {
GST_DEBUG_OBJECT (ac3parse, "bad fscod=%d frmsizcod=%d", fscod, frmsizcod);
return FALSE;
goto cleanup;
}
bsid = gst_bit_reader_get_bits_uint8_unchecked (&bits, 5);
......@@ -262,7 +268,7 @@ gst_ac3_parse_frame_header_ac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
* but seemingly only defines 6 and 8 cases */
if (bsid > 8) {
GST_DEBUG_OBJECT (ac3parse, "unexpected bsid=%d", bsid);
return FALSE;
goto cleanup;
} else if (bsid != 8 && bsid != 6) {
GST_DEBUG_OBJECT (ac3parse, "undefined bsid=%d", bsid);
}
......@@ -287,24 +293,35 @@ gst_ac3_parse_frame_header_ac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
if (sid)
*sid = 0;
return TRUE;
ret = TRUE;
cleanup:
gst_buffer_unmap (buf, data, size);
return ret;
}
static gboolean
gst_ac3_parse_frame_header_eac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
guint * frame_size, guint * rate, guint * chans, guint * blks, guint * sid)
{
GstBitReader bits = GST_BIT_READER_INIT_FROM_BUFFER (buf);
GstBitReader bits;
gpointer data;
gsize size;
guint16 frmsiz, sample_rate, blocks;
guint8 strmtyp, fscod, fscod2, acmod, lfe_on, strmid, numblkscod;
gboolean ret = FALSE;
GST_LOG_OBJECT (ac3parse, "parsing e-ac3");
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
gst_bit_reader_init (&bits, data, size);
gst_bit_reader_skip_unchecked (&bits, 16);
strmtyp = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2); /* strmtyp */
if (G_UNLIKELY (strmtyp == 3)) {
GST_DEBUG_OBJECT (ac3parse, "bad strmtyp %d", strmtyp);
return FALSE;
goto cleanup;
}
strmid = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3); /* substreamid */
......@@ -314,7 +331,7 @@ gst_ac3_parse_frame_header_eac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
fscod2 = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2); /* fscod2 */
if (G_UNLIKELY (fscod2 == 3)) {
GST_DEBUG_OBJECT (ac3parse, "invalid fscod2");
return FALSE;
goto cleanup;
}
sample_rate = fscod_rates[fscod2] / 2;
blocks = 6;
......@@ -340,7 +357,12 @@ gst_ac3_parse_frame_header_eac3 (GstAc3Parse * ac3parse, GstBuffer * buf,
if (sid)
*sid = (strmtyp & 0x1) << 3 | strmid;
return TRUE;
ret = TRUE;
cleanup:
gst_buffer_unmap (buf, data, size);
return ret;
}
static gboolean
......@@ -348,35 +370,49 @@ gst_ac3_parse_frame_header (GstAc3Parse * parse, GstBuffer * buf,
guint * framesize, guint * rate, guint * chans, guint * blocks,
guint * sid, gboolean * eac)
{
GstBitReader bits = GST_BIT_READER_INIT_FROM_BUFFER (buf);
GstBitReader bits;
guint16 sync;
guint8 bsid;
gpointer data;
gsize size;
gboolean ret = FALSE;
GST_MEMDUMP_OBJECT (parse, "AC3 frame sync", GST_BUFFER_DATA (buf), 16);
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
gst_bit_reader_init (&bits, data, size);
GST_MEMDUMP_OBJECT (parse, "AC3 frame sync", data, MIN (size, 16));
sync = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16);
gst_bit_reader_skip_unchecked (&bits, 16 + 8);
bsid = gst_bit_reader_peek_bits_uint8_unchecked (&bits, 5);
if (G_UNLIKELY (sync != 0x0b77))
return FALSE;
goto cleanup;
GST_LOG_OBJECT (parse, "bsid = %d", bsid);
if (bsid <= 10) {
if (eac)
*eac = FALSE;
return gst_ac3_parse_frame_header_ac3 (parse, buf, framesize, rate, chans,
ret = gst_ac3_parse_frame_header_ac3 (parse, buf, framesize, rate, chans,
blocks, sid);
} else if (bsid <= 16) {
goto cleanup;
}
if (bsid <= 16) {
if (eac)
*eac = TRUE;
return gst_ac3_parse_frame_header_eac3 (parse, buf, framesize, rate, chans,
ret = gst_ac3_parse_frame_header_eac3 (parse, buf, framesize, rate, chans,
blocks, sid);
} else {
GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);
return FALSE;
goto cleanup;
}
GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid);
cleanup:
gst_buffer_unmap (buf, data, size);
return ret;
}
static gboolean
......@@ -385,35 +421,40 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse,
{
GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
GstBuffer *buf = frame->buffer;
GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
GstByteReader reader;
gint off;
gboolean lost_sync, draining;
gpointer data;
gsize size;
gboolean ret = FALSE;
if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < 6))
return FALSE;
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
if (G_UNLIKELY (size < 6))
goto cleanup;
off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000,
0, GST_BUFFER_SIZE (buf));
0, size);
GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);
/* didn't find anything that looks like a sync word, skip */
if (off < 0) {
*skipsize = GST_BUFFER_SIZE (buf) - 3;
return FALSE;
*skipsize = size - 3;
goto cleanup;
}
/* possible frame header, but not at offset 0? skip bytes before sync */
if (off > 0) {
*skipsize = off;
return FALSE;
goto cleanup;
}
/* make sure the values in the frame header look sane */
if (!gst_ac3_parse_frame_header (ac3parse, buf, framesize, NULL, NULL,
NULL, NULL, NULL)) {
*skipsize = off + 2;
return FALSE;
goto cleanup;
}
GST_LOG_OBJECT (parse, "got frame");
......@@ -431,12 +472,12 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse,
GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data");
gst_base_parse_set_min_frame_size (parse, *framesize + 6);
*skipsize = 0;
return FALSE;
goto cleanup;
} else {
if (word != 0x0b77) {
GST_DEBUG_OBJECT (ac3parse, "0x%x not OK", word);
*skipsize = off + 2;
return FALSE;
goto cleanup;
} else {
/* ok, got sync now, let's assume constant frame size */
gst_base_parse_set_min_frame_size (parse, *framesize);
......@@ -444,7 +485,12 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse,
}
}
return TRUE;
ret = TRUE;
cleanup:
gst_buffer_unmap (buf, data, size);
return ret;
}
static GstFlowReturn
......@@ -480,7 +526,6 @@ gst_ac3_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
GstCaps *caps = gst_caps_new_simple (eac ? "audio/x-eac3" : "audio/x-ac3",
"framed", G_TYPE_BOOLEAN, TRUE, "rate", G_TYPE_INT, rate,
"channels", G_TYPE_INT, chans, NULL);
gst_buffer_set_caps (buf, caps);
gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
gst_caps_unref (caps);
......
......@@ -78,27 +78,14 @@ static gboolean gst_dca_parse_check_valid_frame (GstBaseParse * parse,
static GstFlowReturn gst_dca_parse_parse_frame (GstBaseParse * parse,
GstBaseParseFrame * frame);
GST_BOILERPLATE (GstDcaParse, gst_dca_parse, GstBaseParse, GST_TYPE_BASE_PARSE);
static void
gst_dca_parse_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_template));
gst_element_class_set_details_simple (element_class,
"DTS Coherent Acoustics audio stream parser", "Codec/Parser/Audio",
"DCA parser", "Tim-Philipp Müller <tim centricular net>");
}
#define gst_dca_parse_parent_class parent_class
G_DEFINE_TYPE (GstDcaParse, gst_dca_parse, GST_TYPE_BASE_PARSE);
static void
gst_dca_parse_class_init (GstDcaParseClass * klass)
{
GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GST_DEBUG_CATEGORY_INIT (dca_parse_debug, "dcaparse", 0,
......@@ -111,6 +98,15 @@ gst_dca_parse_class_init (GstDcaParseClass * klass)
parse_class->check_valid_frame =
GST_DEBUG_FUNCPTR (gst_dca_parse_check_valid_frame);
parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_dca_parse_parse_frame);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_template));
gst_element_class_set_details_simple (element_class,
"DTS Coherent Acoustics audio stream parser", "Codec/Parser/Audio",
"DCA parser", "Tim-Philipp Müller <tim centricular net>");
}
static void
......@@ -126,7 +122,7 @@ gst_dca_parse_reset (GstDcaParse * dcaparse)
}
static void
gst_dca_parse_init (GstDcaParse * dcaparse, GstDcaParseClass * klass)
gst_dca_parse_init (GstDcaParse * dcaparse)
{
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (dcaparse),
DCA_MIN_FRAMESIZE);
......@@ -255,7 +251,7 @@ gst_dca_parse_parse_header (GstDcaParse * dcaparse,
static gint
gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader,
const GstBuffer * buf, guint32 * sync)
gsize bufsize, guint32 * sync)
{
guint32 best_sync = 0;
guint best_offset = G_MAXUINT;
......@@ -265,7 +261,7 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader,
/* Raw little endian */
off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0xfe7f0180,
0, GST_BUFFER_SIZE (buf));
0, bufsize);
if (off >= 0 && off < best_offset) {
best_offset = off;
best_sync = 0xfe7f0180;
......@@ -273,7 +269,7 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader,
/* Raw big endian */
off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x7ffe8001,
0, GST_BUFFER_SIZE (buf));
0, bufsize);
if (off >= 0 && off < best_offset) {
best_offset = off;
best_sync = 0x7ffe8001;
......@@ -284,7 +280,7 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader,
/* 14-bit little endian */
off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0xff1f00e8,
0, GST_BUFFER_SIZE (buf));
0, bufsize);
if (off >= 0 && off < best_offset) {
best_offset = off;
best_sync = 0xff1f00e8;
......@@ -292,7 +288,7 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader,
/* 14-bit big endian */
off = gst_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x1fffe800,
0, GST_BUFFER_SIZE (buf));
0, bufsize);
if (off >= 0 && off < best_offset) {
best_offset = off;
best_sync = 0x1fffe800;
......@@ -311,33 +307,40 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse,
{
GstDcaParse *dcaparse = GST_DCA_PARSE (parse);
GstBuffer *buf = frame->buffer;
GstByteReader r = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
GstByteReader r;
gboolean parser_draining;
gboolean parser_in_sync;
gboolean terminator;
guint32 sync = 0;
guint size, rate, chans, num_blocks, samples_per_block;
gint off = -1;
gpointer data;
gsize bufsize;
gboolean ret = FALSE;
if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < 16))
return FALSE;
data = gst_buffer_map (buf, &bufsize, NULL, GST_MAP_READ);
if (G_UNLIKELY (bufsize < 16))
goto cleanup;
parser_in_sync = !GST_BASE_PARSE_LOST_SYNC (parse);
gst_byte_reader_init (&r, data, bufsize);
if (G_LIKELY (parser_in_sync && dcaparse->last_sync != 0)) {
off = gst_byte_reader_masked_scan_uint32 (&r, 0xffffffff,
dcaparse->last_sync, 0, GST_BUFFER_SIZE (buf));
dcaparse->last_sync, 0, size);
}
if (G_UNLIKELY (off < 0)) {
off = gst_dca_parse_find_sync (dcaparse, &r, buf, &sync);
off = gst_dca_parse_find_sync (dcaparse, &r, bufsize, &sync);
}
/* didn't find anything that looks like a sync word, skip */
if (off < 0) {
*skipsize = GST_BUFFER_SIZE (buf) - 3;
*skipsize = bufsize - 3;
GST_DEBUG_OBJECT (dcaparse, "no sync, skipping %d bytes", *skipsize);
return FALSE;
goto cleanup;
}
GST_LOG_OBJECT (parse, "possible sync %08x at buffer offset %d", sync, off);
......@@ -345,14 +348,14 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse,
/* possible frame header, but not at offset 0? skip bytes before sync */
if (off > 0) {
*skipsize = off;
return FALSE;
goto cleanup;
}
/* make sure the values in the frame header look sane */
if (!gst_dca_parse_parse_header (dcaparse, &r, &size, &rate, &chans, NULL,
NULL, &num_blocks, &samples_per_block, &terminator)) {
*skipsize = 4;
return FALSE;
goto cleanup;
}
GST_LOG_OBJECT (parse, "got frame, sync %08x, size %u, rate %d, channels %d",
......@@ -367,19 +370,19 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse,
if (!parser_in_sync && !parser_draining) {
/* check for second frame to be sure */
GST_DEBUG_OBJECT (dcaparse, "resyncing; checking next frame syncword");
if (GST_BUFFER_SIZE (buf) >= (size + 16)) {
if (bufsize >= (size + 16)) {
guint s2, r2, c2, n2, s3;
gboolean t;
GST_MEMDUMP ("buf", GST_BUFFER_DATA (buf), size + 16);
gst_byte_reader_init_from_buffer (&r, buf);
GST_MEMDUMP ("buf", data, size + 16);
gst_byte_reader_init (&r, data, bufsize);
gst_byte_reader_skip_unchecked (&r, size);
if (!gst_dca_parse_parse_header (dcaparse, &r, &s2, &r2, &c2, NULL, NULL,
&n2, &s3, &t)) {
GST_DEBUG_OBJECT (dcaparse, "didn't find second syncword");
*skipsize = 4;
return FALSE;
goto cleanup;
}
/* ok, got sync now, let's assume constant frame size */
......@@ -388,13 +391,17 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse,
/* FIXME: baseparse always seems to hand us buffers of min_frame_size
* bytes, which is unhelpful here */
GST_LOG_OBJECT (dcaparse, "next sync out of reach (%u < %u)",
GST_BUFFER_SIZE (buf), size + 16);
bufsize, size + 16);
/* *skipsize = 0; */
/* return FALSE; */
}
}
return TRUE;
ret = TRUE;
cleanup:
gst_buffer_unmap (buf, data, bufsize);
return ret;
}
static GstFlowReturn
......@@ -402,10 +409,15 @@ gst_dca_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
{
GstDcaParse *dcaparse = GST_DCA_PARSE (parse);
GstBuffer *buf = frame->buffer;
GstByteReader r = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
GstByteReader r;
guint size, rate, chans, depth, block_size, num_blocks, samples_per_block;
gint endianness;
gboolean terminator;
gpointer data;
gsize bufsize;
data = gst_buffer_map (buf, &bufsize, NULL, GST_MAP_READ);
gst_byte_reader_init (&r, data, bufsize);
if (!gst_dca_parse_parse_header (dcaparse, &r, &size, &rate, &chans, &depth,
&endianness, &num_blocks, &samples_per_block, &terminator))
......@@ -425,7 +437,6 @@ gst_dca_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
"endianness", G_TYPE_INT, endianness, "depth", G_TYPE_INT, depth,
"block-size", G_TYPE_INT, block_size, "frame-size", G_TYPE_INT, size,
NULL);
gst_buffer_set_caps (buf, caps);
gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
gst_caps_unref (caps);
......@@ -439,6 +450,7 @@ gst_dca_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gst_base_parse_set_frame_rate (parse, rate, block_size, 0, 0);
}
gst_buffer_unmap (buf, data, bufsize);
return GST_FLOW_OK;
/* ERRORS */
......@@ -446,6 +458,7 @@ broken_header:
{
/* this really shouldn't ever happen */
GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), (NULL));
gst_buffer_unmap (buf, data, bufsize);
return GST_FLOW_ERROR;
}
}
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment