From 7389cb1513b8b91314058eeb7f6999ea1e6c2b40 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 6 Jun 2011 20:43:31 +0200 Subject: [PATCH] audioparsers: fix some more parsers --- gst/audioparsers/gstaacparse.c | 14 +- gst/audioparsers/gstac3parse.c | 103 +++++--- gst/audioparsers/gstdcaparse.c | 91 ++++--- gst/audioparsers/gstflacparse.c | 366 ++++++++++++++++----------- gst/audioparsers/gstmpegaudioparse.c | 131 ++++++---- 5 files changed, 434 insertions(+), 271 deletions(-) diff --git a/gst/audioparsers/gstaacparse.c b/gst/audioparsers/gstaacparse.c index 711904d9dc..f84633bd27 100644 --- a/gst/audioparsers/gstaacparse.c +++ b/gst/audioparsers/gstaacparse.c @@ -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); diff --git a/gst/audioparsers/gstac3parse.c b/gst/audioparsers/gstac3parse.c index b955c6970d..95698060cb 100644 --- a/gst/audioparsers/gstac3parse.c +++ b/gst/audioparsers/gstac3parse.c @@ -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); diff --git a/gst/audioparsers/gstdcaparse.c b/gst/audioparsers/gstdcaparse.c index 2bf0e38828..b4bbe87245 100644 --- a/gst/audioparsers/gstdcaparse.c +++ b/gst/audioparsers/gstdcaparse.c @@ -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 "); -} +#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 "); } 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; } } diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 0c6c529875..3b2ff365a6 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -202,34 +202,19 @@ static gboolean gst_flac_parse_convert (GstBaseParse * parse, GstFormat src_format, gint64 src_value, GstFormat dest_format, gint64 * dest_value); -GST_BOILERPLATE (GstFlacParse, gst_flac_parse, GstBaseParse, - GST_TYPE_BASE_PARSE); - -static void -gst_flac_parse_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory)); - - gst_element_class_set_details_simple (element_class, "FLAC audio parser", - "Codec/Parser/Audio", - "Parses audio with the FLAC lossless audio codec", - "Sebastian Dröge "); - - GST_DEBUG_CATEGORY_INIT (flacparse_debug, "flacparse", 0, - "Flac parser element"); -} +#define gst_flac_parse_parent_class parent_class +G_DEFINE_TYPE (GstFlacParse, gst_flac_parse, GST_TYPE_BASE_PARSE); static void gst_flac_parse_class_init (GstFlacParseClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstBaseParseClass *baseparse_class = GST_BASE_PARSE_CLASS (klass); + GST_DEBUG_CATEGORY_INIT (flacparse_debug, "flacparse", 0, + "Flac parser element"); + gobject_class->finalize = gst_flac_parse_finalize; gobject_class->set_property = gst_flac_parse_set_property; gobject_class->get_property = gst_flac_parse_get_property; @@ -248,10 +233,20 @@ gst_flac_parse_class_init (GstFlacParseClass * klass) baseparse_class->pre_push_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_frame); baseparse_class->convert = GST_DEBUG_FUNCPTR (gst_flac_parse_convert); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_factory)); + + gst_element_class_set_details_simple (element_class, "FLAC audio parser", + "Codec/Parser/Audio", + "Parses audio with the FLAC lossless audio codec", + "Sebastian Dröge "); } static void -gst_flac_parse_init (GstFlacParse * flacparse, GstFlacParseClass * klass) +gst_flac_parse_init (GstFlacParse * flacparse) { flacparse->check_frame_checksums = DEFAULT_CHECK_FRAME_CHECKSUMS; } @@ -571,15 +566,16 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, GstBaseParseFrame * frame, guint * ret) { GstBuffer *buffer; - const guint8 *data; - guint max, size, remaining; + guint8 *data; + gsize size; + guint max, remaining; guint i, search_start, search_end; FrameHeaderCheckReturn header_ret; guint16 block_size; + gboolean result = FALSE; buffer = frame->buffer; - data = GST_BUFFER_DATA (buffer); - size = GST_BUFFER_SIZE (buffer); + data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); if (size <= flacparse->min_framesize) goto need_more; @@ -589,10 +585,10 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, &block_size); if (header_ret == FRAME_HEADER_INVALID) { *ret = 0; - return FALSE; - } else if (header_ret == FRAME_HEADER_MORE_DATA) { - goto need_more; + goto cleanup; } + if (header_ret == FRAME_HEADER_MORE_DATA) + goto need_more; /* mind unknown framesize */ search_start = MAX (2, flacparse->min_framesize); @@ -619,7 +615,8 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, } *ret = i; flacparse->block_size = block_size; - return TRUE; + result = TRUE; + goto cleanup; } else if (header_ret == FRAME_HEADER_MORE_DATA) { goto need_more; } @@ -635,12 +632,14 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, if (actual_crc == expected_crc) { *ret = size; flacparse->block_size = block_size; - return TRUE; + result = TRUE; + goto cleanup; } } else { *ret = size; flacparse->block_size = block_size; - return TRUE; + result = TRUE; + goto cleanup; } } @@ -649,7 +648,11 @@ need_more: if (max == 16) max = 1 << 24; *ret = MIN (size + 4096, max); - return FALSE; + result = TRUE; + +cleanup: + gst_buffer_unmap (buffer, data, size); + return result; } static gboolean @@ -658,100 +661,124 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, { GstFlacParse *flacparse = GST_FLAC_PARSE (parse); GstBuffer *buffer = frame->buffer; - const guint8 *data = GST_BUFFER_DATA (buffer); + guint8 *data; + gsize bufsize; + gboolean result = TRUE; - if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 4)) - return FALSE; + data = gst_buffer_map (buffer, &bufsize, NULL, GST_MAP_READ); + + if (G_UNLIKELY (bufsize < 4)) { + result = FALSE; + goto cleanup; + } if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) { - if (memcmp (GST_BUFFER_DATA (buffer), "fLaC", 4) == 0) { + if (memcmp (data, "fLaC", 4) == 0) { GST_DEBUG_OBJECT (flacparse, "fLaC marker found"); *framesize = 4; - return TRUE; - } else if (data[0] == 0xff && (data[1] >> 2) == 0x3e) { + goto cleanup; + } + if (data[0] == 0xff && (data[1] >> 2) == 0x3e) { GST_DEBUG_OBJECT (flacparse, "Found headerless FLAC"); /* Minimal size of a frame header */ gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 9); flacparse->state = GST_FLAC_PARSE_STATE_GENERATE_HEADERS; *skipsize = 0; - return FALSE; - } else { - GST_DEBUG_OBJECT (flacparse, "fLaC marker not found"); - return FALSE; + result = FALSE; + goto cleanup; } - } else if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) { + GST_DEBUG_OBJECT (flacparse, "fLaC marker not found"); + result = FALSE; + goto cleanup; + } + + if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) { guint size = 4 + ((data[1] << 16) | (data[2] << 8) | (data[3])); GST_DEBUG_OBJECT (flacparse, "Found metadata block of size %u", size); *framesize = size; - return TRUE; - } else { - if ((GST_READ_UINT16_BE (data) & 0xfffe) == 0xfff8) { - gboolean ret; - guint next; + goto cleanup; + } - flacparse->offset = GST_BUFFER_OFFSET (buffer); - flacparse->blocking_strategy = 0; - flacparse->block_size = 0; - flacparse->sample_number = 0; + if ((GST_READ_UINT16_BE (data) & 0xfffe) == 0xfff8) { + gboolean ret; + guint next; - GST_DEBUG_OBJECT (flacparse, "Found sync code"); - ret = gst_flac_parse_frame_is_valid (flacparse, frame, &next); - if (ret) { - *framesize = next; - return TRUE; - } else { - /* If we're at EOS and the frame was not valid, drop it! */ - if (G_UNLIKELY (GST_BASE_PARSE_DRAINING (flacparse))) { - GST_WARNING_OBJECT (flacparse, "EOS"); - return FALSE; - } + flacparse->offset = GST_BUFFER_OFFSET (buffer); + flacparse->blocking_strategy = 0; + flacparse->block_size = 0; + flacparse->sample_number = 0; - if (next == 0) { - } else if (next > GST_BUFFER_SIZE (buffer)) { - GST_DEBUG_OBJECT (flacparse, "Requesting %u bytes", next); - *skipsize = 0; - gst_base_parse_set_min_frame_size (parse, next); - return FALSE; - } else { - GST_ERROR_OBJECT (flacparse, - "Giving up on invalid frame (%d bytes)", - GST_BUFFER_SIZE (buffer)); - return FALSE; - } - } + GST_DEBUG_OBJECT (flacparse, "Found sync code"); + ret = gst_flac_parse_frame_is_valid (flacparse, frame, &next); + if (ret) { + *framesize = next; + goto cleanup; } else { - GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer); - gint off; - - off = - gst_byte_reader_masked_scan_uint32 (&reader, 0xfffc0000, 0xfff80000, - 0, GST_BUFFER_SIZE (buffer)); - - if (off > 0) { - GST_DEBUG_OBJECT (parse, "Possible sync at buffer offset %d", off); - *skipsize = off; - return FALSE; - } else { - GST_DEBUG_OBJECT (flacparse, "Sync code not found"); - *skipsize = GST_BUFFER_SIZE (buffer) - 3; - return FALSE; + /* If we're at EOS and the frame was not valid, drop it! */ + if (G_UNLIKELY (GST_BASE_PARSE_DRAINING (flacparse))) { + GST_WARNING_OBJECT (flacparse, "EOS"); + result = FALSE; + goto cleanup; } + + if (next == 0) { + } else if (next > bufsize) { + GST_DEBUG_OBJECT (flacparse, "Requesting %u bytes", next); + *skipsize = 0; + gst_base_parse_set_min_frame_size (parse, next); + result = FALSE; + goto cleanup; + } else { + GST_ERROR_OBJECT (flacparse, + "Giving up on invalid frame (%d bytes)", bufsize); + result = FALSE; + goto cleanup; + } + } + } else { + GstByteReader reader; + gint off; + + gst_byte_reader_init (&reader, data, bufsize); + off = + gst_byte_reader_masked_scan_uint32 (&reader, 0xfffc0000, 0xfff80000, + 0, bufsize); + + if (off > 0) { + GST_DEBUG_OBJECT (parse, "Possible sync at buffer offset %d", off); + *skipsize = off; + result = FALSE; + goto cleanup; + } else { + GST_DEBUG_OBJECT (flacparse, "Sync code not found"); + *skipsize = bufsize - 3; + result = FALSE; + goto cleanup; } } - return FALSE; + result = FALSE; + +cleanup: + gst_buffer_unmap (buffer, data, bufsize); + return result; } static gboolean gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer) { - GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer); + GstBitReader reader; + guint8 *data; + gsize size; - if (GST_BUFFER_SIZE (buffer) != 4 + 34) { + data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); + gst_bit_reader_init (&reader, data, size); + + if (size != 4 + 34) { GST_ERROR_OBJECT (flacparse, "Invalid metablock size for STREAMINFO: %u", - GST_BUFFER_SIZE (buffer)); - return FALSE; + size); + goto failure; } /* Skip metadata block header */ @@ -780,7 +807,7 @@ gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer) goto error; if (flacparse->samplerate == 0) { GST_ERROR_OBJECT (flacparse, "Invalid sample rate 0"); - return FALSE; + goto failure; } if (!gst_bit_reader_get_bits_uint8 (&reader, &flacparse->channels, 3)) @@ -789,7 +816,7 @@ gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer) if (flacparse->channels > 8) { GST_ERROR_OBJECT (flacparse, "Invalid number of channels %u", flacparse->channels); - return FALSE; + goto failure; } if (!gst_bit_reader_get_bits_uint8 (&reader, &flacparse->bps, 5)) @@ -803,6 +830,8 @@ gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer) GST_FORMAT_DEFAULT, flacparse->total_samples, 0); } + gst_buffer_unmap (buffer, data, size); + GST_DEBUG_OBJECT (flacparse, "STREAMINFO:\n" "\tmin/max blocksize: %u/%u,\n" "\tmin/max framesize: %u/%u,\n" @@ -819,6 +848,8 @@ gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer) error: GST_ERROR_OBJECT (flacparse, "Failed to read data"); +failure: + gst_buffer_unmap (buffer, data, size); return FALSE; } @@ -826,8 +857,13 @@ static gboolean gst_flac_parse_handle_vorbiscomment (GstFlacParse * flacparse, GstBuffer * buffer) { - flacparse->tags = gst_tag_list_from_vorbiscomment_buffer (buffer, - GST_BUFFER_DATA (buffer), 4, NULL); + guint8 *data; + gsize size; + + data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); + + flacparse->tags = gst_tag_list_from_vorbiscomment (data, size, data, 4, NULL); + gst_buffer_unmap (buffer, data, size); if (flacparse->tags == NULL) { GST_ERROR_OBJECT (flacparse, "Invalid vorbiscomment block"); @@ -842,11 +878,15 @@ gst_flac_parse_handle_vorbiscomment (GstFlacParse * flacparse, static gboolean gst_flac_parse_handle_picture (GstFlacParse * flacparse, GstBuffer * buffer) { - GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer); - const guint8 *data = GST_BUFFER_DATA (buffer); + GstByteReader reader; + guint8 *data; + gsize bufsize; guint32 img_len = 0, img_type = 0; guint32 img_mimetype_len = 0, img_description_len = 0; + data = gst_buffer_map (buffer, &bufsize, NULL, GST_MAP_READ); + gst_byte_reader_init (&reader, data, bufsize); + if (!gst_byte_reader_skip (&reader, 4)) goto error; @@ -880,10 +920,12 @@ gst_flac_parse_handle_picture (GstFlacParse * flacparse, GstBuffer * buffer) flacparse->tags = NULL; } + gst_buffer_unmap (buffer, data, bufsize); return TRUE; error: GST_ERROR_OBJECT (flacparse, "Error reading data"); + gst_buffer_unmap (buffer, data, bufsize); return FALSE; } @@ -904,6 +946,8 @@ gst_flac_parse_process_seektable (GstFlacParse * flacparse, gint64 boffset) { GstByteReader br; gint64 offset = 0, samples = 0; + gpointer data; + gsize bufsize; GST_DEBUG_OBJECT (flacparse, "parsing seektable; base offset %" G_GINT64_FORMAT, boffset); @@ -911,7 +955,9 @@ gst_flac_parse_process_seektable (GstFlacParse * flacparse, gint64 boffset) if (boffset <= 0) goto done; - gst_byte_reader_init_from_buffer (&br, flacparse->seektable); + data = gst_buffer_map (flacparse->seektable, &bufsize, NULL, GST_MAP_READ); + gst_byte_reader_init (&br, data, bufsize); + /* skip header */ if (!gst_byte_reader_skip (&br, 4)) goto done; @@ -937,6 +983,7 @@ gst_flac_parse_process_seektable (GstFlacParse * flacparse, gint64 boffset) } done: + gst_buffer_unmap (flacparse->seektable, data, bufsize); gst_buffer_unref (flacparse->seektable); flacparse->seektable = NULL; } @@ -978,8 +1025,10 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) for (l = flacparse->headers; l; l = l->next) { GstBuffer *header = l->data; - const guint8 *data = GST_BUFFER_DATA (header); - guint size = GST_BUFFER_SIZE (header); + guint8 *data; + gsize size; + + data = gst_buffer_map (header, &size, NULL, GST_MAP_READ); GST_BUFFER_FLAG_SET (header, GST_BUFFER_FLAG_IN_CAPS); @@ -990,6 +1039,8 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) } else if (size > 1 && (data[0] & 0x7f) == 4) { vorbiscomment = header; } + + gst_buffer_unmap (header, data, size); } if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) { @@ -1005,21 +1056,29 @@ gst_flac_parse_handle_headers (GstFlacParse * flacparse) { GstBuffer *buf; guint16 num; + guint8 *sinfodata, *writedata; + gsize sinfosize, writesize; + + sinfodata = gst_buffer_map (streaminfo, &sinfosize, NULL, GST_MAP_READ); /* minus one for the marker that is merged with streaminfo here */ num = g_list_length (flacparse->headers) - 1; - buf = gst_buffer_new_and_alloc (13 + GST_BUFFER_SIZE (streaminfo)); - GST_BUFFER_DATA (buf)[0] = 0x7f; - memcpy (GST_BUFFER_DATA (buf) + 1, "FLAC", 4); - GST_BUFFER_DATA (buf)[5] = 0x01; /* mapping version major */ - GST_BUFFER_DATA (buf)[6] = 0x00; /* mapping version minor */ - GST_BUFFER_DATA (buf)[7] = (num & 0xFF00) >> 8; - GST_BUFFER_DATA (buf)[8] = (num & 0x00FF) >> 0; - memcpy (GST_BUFFER_DATA (buf) + 9, "fLaC", 4); - memcpy (GST_BUFFER_DATA (buf) + 13, GST_BUFFER_DATA (streaminfo), - GST_BUFFER_SIZE (streaminfo)); + buf = gst_buffer_new_and_alloc (13 + sinfosize); + writedata = gst_buffer_map (buf, &writesize, NULL, GST_MAP_WRITE); + + writedata[0] = 0x7f; + memcpy (writedata + 1, "FLAC", 4); + writedata[5] = 0x01; /* mapping version major */ + writedata[6] = 0x00; /* mapping version minor */ + writedata[7] = (num & 0xFF00) >> 8; + writedata[8] = (num & 0x00FF) >> 0; + memcpy (writedata + 9, "fLaC", 4); + memcpy (writedata + 13, sinfodata, sinfosize); _value_array_append_buffer (&array, buf); + + gst_buffer_unmap (streaminfo, sinfodata, sinfosize); + gst_buffer_unmap (buf, writedata, writesize); gst_buffer_unref (buf); } @@ -1053,9 +1112,7 @@ push_headers: flacparse->headers = g_list_delete_link (flacparse->headers, flacparse->headers); - buf = gst_buffer_make_metadata_writable (buf); - gst_buffer_set_caps (buf, - GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (flacparse)))); + buf = gst_buffer_make_writable (buf); /* init, set and give away frame */ gst_base_parse_frame_init (&frame); @@ -1079,9 +1136,12 @@ gst_flac_parse_generate_headers (GstFlacParse * flacparse) { GstBuffer *marker, *streaminfo, *vorbiscomment; guint8 *data; + gsize bufsize; marker = gst_buffer_new_and_alloc (4); - memcpy (GST_BUFFER_DATA (marker), "fLaC", 4); + data = gst_buffer_map (marker, &bufsize, NULL, GST_MAP_WRITE); + memcpy (data, "fLaC", 4); + gst_buffer_unmap (marker, data, bufsize); GST_BUFFER_TIMESTAMP (marker) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (marker) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET (marker) = 0; @@ -1089,7 +1149,7 @@ gst_flac_parse_generate_headers (GstFlacParse * flacparse) flacparse->headers = g_list_append (flacparse->headers, marker); streaminfo = gst_buffer_new_and_alloc (4 + 34); - data = GST_BUFFER_DATA (streaminfo); + data = gst_buffer_map (streaminfo, &bufsize, NULL, GST_MAP_WRITE); memset (data, 0, 4 + 34); /* metadata block header */ @@ -1138,6 +1198,7 @@ gst_flac_parse_generate_headers (GstFlacParse * flacparse) } /* MD5 = 0; */ + gst_buffer_unmap (streaminfo, data, bufsize); GST_BUFFER_TIMESTAMP (streaminfo) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (streaminfo) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET (streaminfo) = 0; @@ -1157,23 +1218,27 @@ gst_flac_parse_generate_headers (GstFlacParse * flacparse) sizeof (header), NULL); gst_tag_list_free (taglist); + data = gst_buffer_map (vorbiscomment, &bufsize, NULL, GST_MAP_WRITE); + /* Get rid of framing bit */ - if (GST_BUFFER_DATA (vorbiscomment)[GST_BUFFER_SIZE (vorbiscomment) - - 1] == 1) { + if (data[bufsize - 1] == 1) { GstBuffer *sub; sub = - gst_buffer_create_sub (vorbiscomment, 0, - GST_BUFFER_SIZE (vorbiscomment) - 1); + gst_buffer_copy_region (vorbiscomment, GST_BUFFER_COPY_ALL, 0, + bufsize - 1); + gst_buffer_unmap (vorbiscomment, data, bufsize); gst_buffer_unref (vorbiscomment); vorbiscomment = sub; + data = gst_buffer_map (vorbiscomment, &bufsize, NULL, GST_MAP_WRITE); } - size = GST_BUFFER_SIZE (vorbiscomment) - 4; - GST_BUFFER_DATA (vorbiscomment)[1] = ((size & 0xFF0000) >> 16); - GST_BUFFER_DATA (vorbiscomment)[2] = ((size & 0x00FF00) >> 8); - GST_BUFFER_DATA (vorbiscomment)[3] = (size & 0x0000FF); + size = bufsize - 4; + data[1] = ((size & 0xFF0000) >> 16); + data[2] = ((size & 0x00FF00) >> 8); + data[3] = (size & 0x0000FF); + gst_buffer_unmap (vorbiscomment, data, bufsize); GST_BUFFER_TIMESTAMP (vorbiscomment) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (vorbiscomment) = GST_CLOCK_TIME_NONE; GST_BUFFER_OFFSET (vorbiscomment) = 0; @@ -1189,7 +1254,11 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstFlacParse *flacparse = GST_FLAC_PARSE (parse); GstBuffer *buffer = frame->buffer; - const guint8 *data = GST_BUFFER_DATA (buffer); + guint8 *data = NULL; + gsize bufsize; + GstFlowReturn res = GST_FLOW_ERROR; + + data = gst_buffer_map (buffer, &bufsize, NULL, GST_MAP_READ); if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) { GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE; @@ -1204,14 +1273,15 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) flacparse->headers = g_list_append (flacparse->headers, gst_buffer_ref (buffer)); - return GST_BASE_PARSE_FLOW_DROPPED; + res = GST_BASE_PARSE_FLOW_DROPPED; } else if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) { gboolean is_last = ((data[0] & 0x80) == 0x80); guint type = (data[0] & 0x7F); if (type == 127) { GST_WARNING_OBJECT (flacparse, "Invalid metadata block type"); - return GST_BASE_PARSE_FLOW_DROPPED; + res = GST_BASE_PARSE_FLOW_DROPPED; + goto cleanup; } GST_DEBUG_OBJECT (flacparse, "Handling metadata block of type %u", type); @@ -1219,19 +1289,19 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) switch (type) { case 0: /* STREAMINFO */ if (!gst_flac_parse_handle_streaminfo (flacparse, buffer)) - return GST_FLOW_ERROR; + goto cleanup; break; case 3: /* SEEKTABLE */ if (!gst_flac_parse_handle_seektable (flacparse, buffer)) - return GST_FLOW_ERROR; + goto cleanup; break; case 4: /* VORBIS_COMMENT */ if (!gst_flac_parse_handle_vorbiscomment (flacparse, buffer)) - return GST_FLOW_ERROR; + goto cleanup; break; case 6: /* PICTURE */ if (!gst_flac_parse_handle_picture (flacparse, buffer)) - return GST_FLOW_ERROR; + goto cleanup; break; case 1: /* PADDING */ case 2: /* APPLICATION */ @@ -1250,7 +1320,7 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) if (is_last) { if (!gst_flac_parse_handle_headers (flacparse)) - return GST_FLOW_ERROR; + goto cleanup; /* Minimal size of a frame header */ gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9, @@ -1259,7 +1329,7 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) } /* DROPPED because we pushed already or will push all headers manually */ - return GST_BASE_PARSE_FLOW_DROPPED; + res = GST_BASE_PARSE_FLOW_DROPPED; } else { if (flacparse->offset != GST_BUFFER_OFFSET (buffer)) { FrameHeaderCheckReturn ret; @@ -1267,17 +1337,17 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) flacparse->offset = GST_BUFFER_OFFSET (buffer); ret = gst_flac_parse_frame_header_is_valid (flacparse, - GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), TRUE, NULL); + data, bufsize, TRUE, NULL); if (ret != FRAME_HEADER_VALID) { GST_ERROR_OBJECT (flacparse, "Baseclass didn't provide a complete frame"); - return GST_FLOW_ERROR; + goto cleanup; } } if (flacparse->block_size == 0) { GST_ERROR_OBJECT (flacparse, "Unparsed frame"); - return GST_FLOW_ERROR; + goto cleanup; } if (flacparse->seektable) @@ -1289,15 +1359,15 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) "Generating headers for variable blocksize streams not supported"); if (!gst_flac_parse_handle_headers (flacparse)) - return GST_FLOW_ERROR; + goto cleanup; } else { GST_DEBUG_OBJECT (flacparse, "Generating headers"); if (!gst_flac_parse_generate_headers (flacparse)) - return GST_FLOW_ERROR; + goto cleanup; if (!gst_flac_parse_handle_headers (flacparse)) - return GST_FLOW_ERROR; + goto cleanup; } flacparse->state = GST_FLAC_PARSE_STATE_DATA; } @@ -1336,8 +1406,14 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) flacparse->blocking_strategy = 0; flacparse->block_size = 0; flacparse->sample_number = 0; - return GST_FLOW_OK; + res = GST_FLOW_OK; } + +cleanup: + if (data) + gst_buffer_unmap (buffer, data, bufsize); + + return res; } static GstFlowReturn diff --git a/gst/audioparsers/gstmpegaudioparse.c b/gst/audioparsers/gstmpegaudioparse.c index 0c55704a91..badc901ff7 100644 --- a/gst/audioparsers/gstmpegaudioparse.c +++ b/gst/audioparsers/gstmpegaudioparse.c @@ -98,8 +98,8 @@ static gboolean gst_mpeg_audio_parse_convert (GstBaseParse * parse, GstFormat src_format, gint64 src_value, GstFormat dest_format, gint64 * dest_value); -GST_BOILERPLATE (GstMpegAudioParse, gst_mpeg_audio_parse, GstBaseParse, - GST_TYPE_BASE_PARSE); +#define gst_mpeg_audio_parse_parent_class parent_class +G_DEFINE_TYPE (GstMpegAudioParse, gst_mpeg_audio_parse, GST_TYPE_BASE_PARSE); #define GST_TYPE_MPEG_AUDIO_CHANNEL_MODE \ (gst_mpeg_audio_channel_mode_get_type()) @@ -137,27 +137,11 @@ gst_mpeg_audio_channel_mode_get_nick (gint mode) return NULL; } -static void -gst_mpeg_audio_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, "MPEG1 Audio Parser", - "Codec/Parser/Audio", - "Parses and frames mpeg1 audio streams (levels 1-3), provides seek", - "Jan Schmidt ," - "Mark Nauwelaerts "); -} - static void gst_mpeg_audio_parse_class_init (GstMpegAudioParseClass * 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 (mpeg_audio_parse_debug, "mpegaudioparse", 0, @@ -185,6 +169,17 @@ gst_mpeg_audio_parse_class_init (GstMpegAudioParseClass * klass) "channel mode", "MPEG audio channel mode", NULL); g_type_class_ref (GST_TYPE_MPEG_AUDIO_CHANNEL_MODE); + + 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, "MPEG1 Audio Parser", + "Codec/Parser/Audio", + "Parses and frames mpeg1 audio streams (levels 1-3), provides seek", + "Jan Schmidt ," + "Mark Nauwelaerts "); } static void @@ -220,8 +215,7 @@ gst_mpeg_audio_parse_reset (GstMpegAudioParse * mp3parse) } static void -gst_mpeg_audio_parse_init (GstMpegAudioParse * mp3parse, - GstMpegAudioParseClass * klass) +gst_mpeg_audio_parse_init (GstMpegAudioParse * mp3parse) { gst_mpeg_audio_parse_reset (mp3parse); } @@ -374,13 +368,13 @@ gst_mp3parse_validate_extended (GstMpegAudioParse * mp3parse, GstBuffer * buf, guint32 header, int bpf, gboolean at_eos, gint * valid) { guint32 next_header; - const guint8 *data; - guint available; + guint8 *data; + gsize available; + gboolean res = TRUE; int frames_found = 1; int offset = bpf; - available = GST_BUFFER_SIZE (buf); - data = GST_BUFFER_DATA (buf); + data = gst_buffer_map (buf, &available, NULL, GST_MAP_READ); while (frames_found < MIN_RESYNC_FRAMES) { /* Check if we have enough data for all these frames, plus the next @@ -389,10 +383,11 @@ gst_mp3parse_validate_extended (GstMpegAudioParse * mp3parse, GstBuffer * buf, if (at_eos) { /* Running out of data at EOS is fine; just accept it */ *valid = TRUE; - return TRUE; + goto cleanup; } else { *valid = offset + 4; - return FALSE; + res = FALSE; + goto cleanup; } } @@ -413,14 +408,14 @@ gst_mp3parse_validate_extended (GstMpegAudioParse * mp3parse, GstBuffer * buf, (guint) header, (guint) header & HDRMASK, (guint) next_header, (guint) next_header & HDRMASK, bpf); *valid = FALSE; - return TRUE; + goto cleanup; } else if ((((next_header >> 12) & 0xf) == 0) || (((next_header >> 12) & 0xf) == 0xf)) { /* The essential parts were the same, but the bitrate held an invalid value - also reject */ GST_DEBUG_OBJECT (mp3parse, "next header invalid (bitrate)"); *valid = FALSE; - return TRUE; + goto cleanup; } bpf = mp3_type_frame_length_from_header (mp3parse, next_header, @@ -431,7 +426,10 @@ gst_mp3parse_validate_extended (GstMpegAudioParse * mp3parse, GstBuffer * buf, } *valid = TRUE; - return TRUE; + +cleanup: + gst_buffer_unmap (buf, data, available); + return res; } static gboolean @@ -487,37 +485,43 @@ gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, { GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse); GstBuffer *buf = frame->buffer; - GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf); + GstByteReader reader; gint off, bpf; gboolean lost_sync, draining, valid, caps_change; guint32 header; guint bitrate, layer, rate, channels, version, mode, crc; + guint8 *data; + gsize bufsize; + gboolean res = FALSE; - if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < 6)) - return FALSE; + data = gst_buffer_map (buf, &bufsize, NULL, GST_MAP_READ); + if (G_UNLIKELY (bufsize < 6)) + goto cleanup; + + gst_byte_reader_init (&reader, data, bufsize); off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffe00000, 0xffe00000, - 0, GST_BUFFER_SIZE (buf)); + 0, bufsize); 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 = bufsize - 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 */ - header = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf)); + header = GST_READ_UINT32_BE (data); if (!gst_mpeg_audio_parse_head_check (mp3parse, header)) { *skipsize = 1; - return FALSE; + goto cleanup; } GST_LOG_OBJECT (parse, "got frame"); @@ -541,21 +545,25 @@ gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, /* not enough data */ gst_base_parse_set_min_frame_size (parse, valid); *skipsize = 0; - return FALSE; + goto cleanup; } else { if (!valid) { *skipsize = off + 2; - return FALSE; + goto cleanup; } } } else if (draining && lost_sync && caps_change && mp3parse->rate > 0) { /* avoid caps jitter that we can't be sure of */ *skipsize = off + 2; - return FALSE; + goto cleanup; } *framesize = bpf; - return TRUE; + res = TRUE; + +cleanup: + gst_buffer_unmap (buf, data, bufsize); + return res; } static void @@ -571,7 +579,8 @@ gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * mp3parse, gint64 upstream_total_bytes = 0; GstFormat fmt = GST_FORMAT_BYTES; guint32 read_id_xing = 0, read_id_vbri = 0; - const guint8 *data; + guint8 *data, *origdata; + gsize bufsize; guint bitrate; if (mp3parse->sent_codec_tag) @@ -598,8 +607,8 @@ gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * mp3parse, offset_vbri += 4; /* Check if we have enough data to read the Xing header */ - avail = GST_BUFFER_SIZE (buf); - data = GST_BUFFER_DATA (buf); + origdata = data = gst_buffer_map (buf, &bufsize, NULL, GST_MAP_READ); + avail = bufsize; if (avail >= offset_xing + 4) { read_id_xing = GST_READ_UINT32_BE (data + offset_xing); @@ -639,7 +648,7 @@ gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * mp3parse, if (avail < bytes_needed) { GST_DEBUG_OBJECT (mp3parse, "Not enough data to read Xing header (need %d)", bytes_needed); - return; + goto cleanup; } GST_DEBUG_OBJECT (mp3parse, "Reading Xing header"); @@ -795,7 +804,7 @@ gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * mp3parse, if (avail < offset_vbri + 26) { GST_DEBUG_OBJECT (mp3parse, "Not enough data to read VBRI header (need %d)", offset_vbri + 26); - return; + goto cleanup; } GST_DEBUG_OBJECT (mp3parse, "Reading VBRI header"); @@ -806,7 +815,7 @@ gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * mp3parse, if (GST_READ_UINT16_BE (data) != 0x0001) { GST_WARNING_OBJECT (mp3parse, "Unsupported VBRI version 0x%x", GST_READ_UINT16_BE (data)); - return; + goto cleanup; } data += 2; @@ -879,10 +888,10 @@ gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * mp3parse, GST_DEBUG_OBJECT (mp3parse, "Not enough data to read VBRI header (need %d)", offset_vbri + 26 + nseek_points * seek_bytes); - return; + goto cleanup; } - data = GST_BUFFER_DATA (buf); + data = origdata; data += offset_vbri + 26; /* VBRI seek table: frame/seek_frames -> byte */ @@ -956,6 +965,9 @@ gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * mp3parse, bitrate = 0; gst_base_parse_set_average_bitrate (GST_BASE_PARSE (mp3parse), bitrate); + +cleanup: + gst_buffer_unmap (buf, origdata, bufsize); } static GstFlowReturn @@ -964,12 +976,16 @@ gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse, { GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse); GstBuffer *buf = frame->buffer; + guint8 *data; + gsize bufsize; guint bitrate, layer, rate, channels, version, mode, crc; - g_return_val_if_fail (GST_BUFFER_SIZE (buf) >= 4, GST_FLOW_ERROR); + data = gst_buffer_map (buf, &bufsize, NULL, GST_MAP_READ); + if (G_UNLIKELY (bufsize < 4)) + goto short_buffer; if (!mp3_type_frame_length_from_header (mp3parse, - GST_READ_UINT32_BE (GST_BUFFER_DATA (buf)), + GST_READ_UINT32_BE (data), &version, &layer, &channels, &bitrate, &rate, &mode, &crc)) goto broken_header; @@ -981,7 +997,6 @@ gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse, "layer", G_TYPE_INT, layer, "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); - gst_buffer_set_caps (buf, caps); gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); gst_caps_unref (caps); @@ -1025,15 +1040,23 @@ gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse, mp3parse->last_crc = crc; mp3parse->last_mode = mode; + gst_buffer_unmap (buf, data, bufsize); return GST_FLOW_OK; /* ERRORS */ broken_header: { /* this really shouldn't ever happen */ + gst_buffer_unmap (buf, data, bufsize); GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), (NULL)); return GST_FLOW_ERROR; } + +short_buffer: + { + gst_buffer_unmap (buf, data, bufsize); + return GST_FLOW_ERROR; + } } static gboolean