From 1ae32656ae80ce31dffe3f33a0bdabb06571c0e1 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Thu, 9 Feb 2012 13:41:53 +0100 Subject: [PATCH] audioparsers: adjust to modified baseparse API --- gst/audioparsers/gstaacparse.c | 138 ++++++++++++---------------- gst/audioparsers/gstac3parse.c | 84 +++++++---------- gst/audioparsers/gstamrparse.c | 56 +++--------- gst/audioparsers/gstdcaparse.c | 82 ++++++----------- gst/audioparsers/gstflacparse.c | 82 ++++++++++------- gst/audioparsers/gstmpegaudioparse.c | 172 ++++++++++++++--------------------- 6 files changed, 256 insertions(+), 358 deletions(-) diff --git a/gst/audioparsers/gstaacparse.c b/gst/audioparsers/gstaacparse.c index cc91747..fed17da 100644 --- a/gst/audioparsers/gstaacparse.c +++ b/gst/audioparsers/gstaacparse.c @@ -89,11 +89,8 @@ static gboolean gst_aac_parse_sink_setcaps (GstBaseParse * parse, static GstCaps *gst_aac_parse_sink_getcaps (GstBaseParse * parse, GstCaps * filter); -static gboolean gst_aac_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * size, gint * skipsize); - -static GstFlowReturn gst_aac_parse_parse_frame (GstBaseParse * parse, - GstBaseParseFrame * frame); +static GstFlowReturn gst_aac_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize); gboolean gst_aac_parse_convert (GstBaseParse * parse, GstFormat src_format, @@ -146,9 +143,7 @@ gst_aac_parse_class_init (GstAacParseClass * klass) parse_class->stop = GST_DEBUG_FUNCPTR (gst_aac_parse_stop); parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_aac_parse_sink_setcaps); parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_aac_parse_sink_getcaps); - parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_aac_parse_parse_frame); - parse_class->check_valid_frame = - GST_DEBUG_FUNCPTR (gst_aac_parse_check_valid_frame); + parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_aac_parse_handle_frame); } @@ -900,48 +895,63 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse, /** * gst_aac_parse_check_valid_frame: * @parse: #GstBaseParse. - * @buffer: #GstBuffer. - * @framesize: If the buffer contains a valid frame, its size will be put here + * @frame: #GstBaseParseFrame. * @skipsize: How much data parent class should skip in order to find the * frame header. * - * Implementation of "check_valid_frame" vmethod in #GstBaseParse class. + * Implementation of "handle_frame" vmethod in #GstBaseParse class. + * + * Also determines frame overhead. + * ADTS streams have a 7 byte header in each frame. MP4 and ADIF streams don't have + * a per-frame header. LOAS has 3 bytes. + * + * We're making a couple of simplifying assumptions: + * + * 1. We count Program Configuration Elements rather than searching for them + * in the streams to discount them - the overhead is negligible. + * + * 2. We ignore CRC. This has a worst-case impact of (num_raw_blocks + 1)*16 + * bits, which should still not be significant enough to warrant the + * additional parsing through the headers * - * Returns: TRUE if buffer contains a valid frame. + * Returns: a #GstFlowReturn. */ -static gboolean -gst_aac_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +static GstFlowReturn +gst_aac_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize) { GstMapInfo map; GstAacParse *aacparse; gboolean ret = FALSE; gboolean lost_sync; GstBuffer *buffer; + guint framesize; + gint rate, channels; aacparse = GST_AAC_PARSE (parse); buffer = frame->buffer; gst_buffer_map (buffer, &map, GST_MAP_READ); + *skipsize = -1; lost_sync = GST_BASE_PARSE_LOST_SYNC (parse); if (aacparse->header_type == DSPAAC_HEADER_ADIF || aacparse->header_type == DSPAAC_HEADER_NONE) { /* There is nothing to parse */ - *framesize = map.size; + framesize = map.size; ret = TRUE; } else if (aacparse->header_type == DSPAAC_HEADER_NOT_PARSED || lost_sync) { ret = gst_aac_parse_detect_stream (aacparse, map.data, map.size, - GST_BASE_PARSE_DRAINING (parse), framesize, skipsize); + GST_BASE_PARSE_DRAINING (parse), &framesize, skipsize); } else if (aacparse->header_type == DSPAAC_HEADER_ADTS) { guint needed_data = 1024; ret = gst_aac_parse_check_adts_frame (aacparse, map.data, map.size, - GST_BASE_PARSE_DRAINING (parse), framesize, &needed_data); + GST_BASE_PARSE_DRAINING (parse), &framesize, &needed_data); if (!ret) { GST_DEBUG ("buffer didn't contain valid frame"); @@ -953,7 +963,7 @@ gst_aac_parse_check_valid_frame (GstBaseParse * parse, guint needed_data = 1024; ret = gst_aac_parse_check_loas_frame (aacparse, map.data, - map.size, GST_BASE_PARSE_DRAINING (parse), framesize, &needed_data); + map.size, GST_BASE_PARSE_DRAINING (parse), &framesize, &needed_data); if (!ret) { GST_DEBUG ("buffer didn't contain valid frame"); @@ -966,72 +976,29 @@ gst_aac_parse_check_valid_frame (GstBaseParse * parse, gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), ADTS_MAX_SIZE); } - gst_buffer_unmap (buffer, &map); - - return ret; -} - -/** - * gst_aac_parse_parse_frame: - * @parse: #GstBaseParse. - * @buffer: #GstBuffer. - * - * Implementation of "parse_frame" vmethod in #GstBaseParse class. - * - * Also determines frame overhead. - * ADTS streams have a 7 byte header in each frame. MP4 and ADIF streams don't have - * a per-frame header. LOAS has 3 bytes. - * - * We're making a couple of simplifying assumptions: - * - * 1. We count Program Configuration Elements rather than searching for them - * in the streams to discount them - the overhead is negligible. - * - * 2. We ignore CRC. This has a worst-case impact of (num_raw_blocks + 1)*16 - * bits, which should still not be significant enough to warrant the - * additional parsing through the headers - * - * Returns: GST_FLOW_OK if frame was successfully parsed and can be pushed - * forward. Otherwise appropriate error is returned. - */ -static GstFlowReturn -gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) -{ - GstAacParse *aacparse; - GstBuffer *buffer; - GstFlowReturn ret = GST_FLOW_OK; - gint rate, channels; - GstMapInfo map; - - aacparse = GST_AAC_PARSE (parse); - buffer = frame->buffer; + if (G_UNLIKELY (!ret)) + goto exit; if (aacparse->header_type == DSPAAC_HEADER_ADTS) { /* see above */ frame->overhead = 7; - gst_buffer_map (buffer, &map, GST_MAP_READ); gst_aac_parse_parse_adts_header (aacparse, map.data, &rate, &channels, NULL, NULL); - gst_buffer_unmap (buffer, &map); GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels); if (G_UNLIKELY (rate != aacparse->sample_rate || channels != aacparse->channels)) { - GstCaps *sinkcaps; - aacparse->sample_rate = rate; aacparse->channels = channels; - if ((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 */ - ret = GST_FLOW_NOT_LINKED; - } - gst_caps_unref (sinkcaps); + GST_DEBUG_OBJECT (aacparse, "here"); + + if (!gst_aac_parse_set_src_caps (aacparse, NULL)) { + /* If linking fails, we need to return appropriate error */ + ret = GST_FLOW_NOT_LINKED; } gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), @@ -1043,7 +1010,6 @@ gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) /* see above */ frame->overhead = 3; - gst_buffer_map (buffer, &map, GST_MAP_READ); if (!gst_aac_parse_read_loas_config (aacparse, map.data, map.size, &rate, &channels, NULL)) { GST_WARNING_OBJECT (aacparse, "Error reading LOAS config"); @@ -1055,22 +1021,15 @@ gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) GST_INFO_OBJECT (aacparse, "New LOAS config: %d Hz, %d channels", rate, channels); } - gst_buffer_unmap (buffer, &map); /* We want to set caps both at start, and when rate/channels change. Since only some LOAS frames have that info, we may receive frames before knowing about rate/channels. */ if (setcaps || !gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (aacparse))) { - GstCaps *sinkcaps; - - if ((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 */ - ret = GST_FLOW_NOT_LINKED; - } - gst_caps_unref (sinkcaps); + if (!gst_aac_parse_set_src_caps (aacparse, NULL)) { + /* If linking fails, we need to return appropriate error */ + ret = GST_FLOW_NOT_LINKED; } gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), @@ -1078,7 +1037,24 @@ gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) } } - return ret; +exit: + gst_buffer_unmap (buffer, &map); + + if (ret) { + /* found, skip if needed */ + if (*skipsize > 0) + return GST_FLOW_OK; + *skipsize = 0; + } else { + if (*skipsize < 0) + *skipsize = 1; + } + + if (ret && framesize <= map.size) { + return gst_base_parse_finish_frame (parse, frame, framesize); + } + + return GST_FLOW_OK; } diff --git a/gst/audioparsers/gstac3parse.c b/gst/audioparsers/gstac3parse.c index 9b1a365..f88972f 100644 --- a/gst/audioparsers/gstac3parse.c +++ b/gst/audioparsers/gstac3parse.c @@ -159,10 +159,8 @@ static void gst_ac3_parse_finalize (GObject * object); static gboolean gst_ac3_parse_start (GstBaseParse * parse); static gboolean gst_ac3_parse_stop (GstBaseParse * parse); -static gboolean gst_ac3_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * size, gint * skipsize); -static GstFlowReturn gst_ac3_parse_parse_frame (GstBaseParse * parse, - GstBaseParseFrame * frame); +static GstFlowReturn gst_ac3_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize); static gboolean gst_ac3_parse_src_event (GstBaseParse * parse, GstEvent * event); static GstCaps *gst_ac3_parse_get_sink_caps (GstBaseParse * parse, @@ -194,9 +192,7 @@ gst_ac3_parse_class_init (GstAc3ParseClass * klass) parse_class->start = GST_DEBUG_FUNCPTR (gst_ac3_parse_start); parse_class->stop = GST_DEBUG_FUNCPTR (gst_ac3_parse_stop); - parse_class->check_valid_frame = - GST_DEBUG_FUNCPTR (gst_ac3_parse_check_valid_frame); - parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_ac3_parse_parse_frame); + parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_ac3_parse_handle_frame); parse_class->src_event = GST_DEBUG_FUNCPTR (gst_ac3_parse_src_event); parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_ac3_parse_get_sink_caps); } @@ -481,9 +477,9 @@ cleanup: return ret; } -static gboolean -gst_ac3_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +static GstFlowReturn +gst_ac3_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize) { GstAc3Parse *ac3parse = GST_AC3_PARSE (parse); GstBuffer *buf = frame->buffer; @@ -491,14 +487,20 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse, gint off; gboolean lost_sync, draining, eac, more = FALSE; guint frmsiz, blocks, sid; + guint rate, chans; + gboolean update_rate = FALSE; + gint framesize = 0; gint have_blocks = 0; GstMapInfo map; gboolean ret = FALSE; + GstFlowReturn res = GST_FLOW_OK; gst_buffer_map (buf, &map, GST_MAP_READ); - if (G_UNLIKELY (map.size < 6)) + if (G_UNLIKELY (map.size < 6)) { + *skipsize = 1; goto cleanup; + } gst_byte_reader_init (&reader, map.data, map.size); off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000, @@ -519,13 +521,16 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse, } /* make sure the values in the frame header look sane */ - if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &frmsiz, NULL, NULL, + if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &frmsiz, &rate, &chans, &blocks, &sid, &eac)) { *skipsize = off + 2; goto cleanup; } - *framesize = frmsiz; + GST_LOG_OBJECT (parse, "size: %u, blocks: %u, rate: %u, chans: %u", frmsiz, + blocks, rate, chans); + + framesize = frmsiz; if (G_UNLIKELY (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_NONE)) @@ -550,21 +555,21 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse, goto cleanup; } - *framesize = 0; + framesize = 0; /* Loop till we have 6 blocks per substream */ for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) { /* Loop till we get one frame from each substream */ do { - *framesize += frmsiz; + framesize += frmsiz; if (!gst_byte_reader_skip (&reader, frmsiz) - || map.size < (*framesize + 6)) { + || map.size < (framesize + 6)) { more = TRUE; break; } - if (!gst_ac3_parse_frame_header (ac3parse, buf, *framesize, &frmsiz, + if (!gst_ac3_parse_frame_header (ac3parse, buf, framesize, &frmsiz, NULL, NULL, NULL, &sid, &eac)) { *skipsize = off + 2; goto cleanup; @@ -584,7 +589,7 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse, if (more || !gst_byte_reader_skip (&reader, frmsiz) || !gst_byte_reader_get_uint16_be (&reader, &word)) { GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data"); - gst_base_parse_set_min_frame_size (parse, *framesize + 6); + gst_base_parse_set_min_frame_size (parse, framesize + 6); *skipsize = 0; goto cleanup; } else { @@ -594,34 +599,16 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse, goto cleanup; } else { /* ok, got sync now, let's assume constant frame size */ - gst_base_parse_set_min_frame_size (parse, *framesize); + gst_base_parse_set_min_frame_size (parse, framesize); } } } + /* expect to have found a frame here */ + g_assert (framesize); ret = TRUE; -cleanup: - gst_buffer_unmap (buf, &map); - - return ret; -} - -static GstFlowReturn -gst_ac3_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) -{ - GstAc3Parse *ac3parse = GST_AC3_PARSE (parse); - GstBuffer *buf = frame->buffer; - guint fsize, rate, chans, blocks, sid; - gboolean eac, update_rate = FALSE; - - if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &fsize, &rate, &chans, - &blocks, &sid, &eac)) - goto broken_header; - - GST_LOG_OBJECT (parse, "size: %u, blocks: %u, rate: %u, chans: %u", fsize, - blocks, rate, chans); - + /* arrange for metadata setup */ if (G_UNLIKELY (sid)) { /* dependent frame, no need to (ac)count for or consider further */ GST_LOG_OBJECT (parse, "sid: %d", sid); @@ -631,9 +618,9 @@ gst_ac3_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) /* occupies same time space as previous base frame */ if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf))) GST_BUFFER_TIMESTAMP (buf) -= GST_BUFFER_DURATION (buf); - /* only return if we already arranged for caps */ + /* only shortcut if we already arranged for caps */ if (G_LIKELY (ac3parse->sample_rate > 0)) - return GST_FLOW_OK; + goto cleanup; } if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans @@ -663,15 +650,14 @@ gst_ac3_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) if (G_UNLIKELY (update_rate)) gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2); - return GST_FLOW_OK; +cleanup: + gst_buffer_unmap (buf, &map); -/* ERRORS */ -broken_header: - { - /* this really shouldn't ever happen */ - GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), (NULL)); - return GST_FLOW_ERROR; + if (ret && framesize <= map.size) { + res = gst_base_parse_finish_frame (parse, frame, framesize); } + + return res; } static gboolean diff --git a/gst/audioparsers/gstamrparse.c b/gst/audioparsers/gstamrparse.c index 974d635..28e64db 100644 --- a/gst/audioparsers/gstamrparse.c +++ b/gst/audioparsers/gstamrparse.c @@ -79,11 +79,8 @@ static gboolean gst_amr_parse_sink_setcaps (GstBaseParse * parse, static GstCaps *gst_amr_parse_sink_getcaps (GstBaseParse * parse, GstCaps * filter); -static gboolean gst_amr_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * framesize, gint * skipsize); - -static GstFlowReturn gst_amr_parse_parse_frame (GstBaseParse * parse, - GstBaseParseFrame * frame); +static GstFlowReturn gst_amr_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize); G_DEFINE_TYPE (GstAmrParse, gst_amr_parse, GST_TYPE_BASE_PARSE); @@ -115,9 +112,7 @@ gst_amr_parse_class_init (GstAmrParseClass * klass) parse_class->stop = GST_DEBUG_FUNCPTR (gst_amr_parse_stop); parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_amr_parse_sink_setcaps); parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_amr_parse_sink_getcaps); - parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_amr_parse_parse_frame); - parse_class->check_valid_frame = - GST_DEBUG_FUNCPTR (gst_amr_parse_check_valid_frame); + parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_amr_parse_handle_frame); } @@ -254,15 +249,16 @@ gst_amr_parse_parse_header (GstAmrParse * amrparse, * * Returns: TRUE if the given data contains valid frame. */ -static gboolean -gst_amr_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +static GstFlowReturn +gst_amr_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize) { GstBuffer *buffer; GstMapInfo map; - gint fsize, mode, dsize; + gint fsize = 0, mode, dsize; GstAmrParse *amrparse; - gboolean ret = FALSE; + GstFlowReturn ret = GST_FLOW_OK; + gboolean found = FALSE; amrparse = GST_AMR_PARSE (parse); buffer = frame->buffer; @@ -285,6 +281,7 @@ gst_amr_parse_check_valid_frame (GstBaseParse * parse, goto done; } + *skipsize = 1; /* Does this look like a possible frame header candidate? */ if ((map.data[0] & 0x83) == 0) { /* Yep. Retrieve the frame size */ @@ -299,8 +296,7 @@ gst_amr_parse_check_valid_frame (GstBaseParse * parse, * perform this check) */ if (fsize) { - gboolean found = FALSE; - + *skipsize = 0; /* in sync, no further check */ if (!GST_BASE_PARSE_LOST_SYNC (parse)) { found = TRUE; @@ -311,42 +307,20 @@ gst_amr_parse_check_valid_frame (GstBaseParse * parse, } else if (GST_BASE_PARSE_DRAINING (parse)) { /* not enough, but draining, so ok */ found = TRUE; - } else { - /* indicate we need not skip, but need more data */ - *skipsize = 0; - *framesize = fsize + 1; - } - if (found) { - *framesize = fsize; - return TRUE; } } } - GST_LOG ("sync lost"); done: gst_buffer_unmap (buffer, &map); - return ret; -} - + if (found && fsize <= map.size) { + ret = gst_base_parse_finish_frame (parse, frame, fsize); + } -/** - * gst_amr_parse_parse_frame: - * @parse: #GstBaseParse. - * @buffer: #GstBuffer. - * - * Implementation of "parse" vmethod in #GstBaseParse class. - * - * Returns: #GstFlowReturn defining the parsing status. - */ -static GstFlowReturn -gst_amr_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) -{ - return GST_FLOW_OK; + return ret; } - /** * gst_amr_parse_start: * @parse: #GstBaseParse. diff --git a/gst/audioparsers/gstdcaparse.c b/gst/audioparsers/gstdcaparse.c index 24aa2a8..b1e256b 100644 --- a/gst/audioparsers/gstdcaparse.c +++ b/gst/audioparsers/gstdcaparse.c @@ -74,10 +74,8 @@ static void gst_dca_parse_finalize (GObject * object); static gboolean gst_dca_parse_start (GstBaseParse * parse); static gboolean gst_dca_parse_stop (GstBaseParse * parse); -static gboolean gst_dca_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * size, gint * skipsize); -static GstFlowReturn gst_dca_parse_parse_frame (GstBaseParse * parse, - GstBaseParseFrame * frame); +static GstFlowReturn gst_dca_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize); static GstCaps *gst_dca_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter); @@ -98,9 +96,7 @@ gst_dca_parse_class_init (GstDcaParseClass * klass) parse_class->start = GST_DEBUG_FUNCPTR (gst_dca_parse_start); parse_class->stop = GST_DEBUG_FUNCPTR (gst_dca_parse_stop); - 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); + parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_dca_parse_handle_frame); parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_dca_parse_get_sink_caps); gst_element_class_add_pad_template (element_class, @@ -305,9 +301,9 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader, return best_offset; } -static gboolean -gst_dca_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +static GstFlowReturn +gst_dca_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize) { GstDcaParse *dcaparse = GST_DCA_PARSE (parse); GstBuffer *buf = frame->buffer; @@ -316,15 +312,19 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse, gboolean parser_in_sync; gboolean terminator; guint32 sync = 0; - guint size, rate, chans, num_blocks, samples_per_block; + guint size, rate, chans, num_blocks, samples_per_block, depth; + gint block_size; + gint endianness; gint off = -1; GstMapInfo map; - gboolean ret = FALSE; + GstFlowReturn ret = GST_FLOW_EOS; gst_buffer_map (buf, &map, GST_MAP_READ); - if (G_UNLIKELY (map.size < 16)) + if (G_UNLIKELY (map.size < 16)) { + *skipsize = 1; goto cleanup; + } parser_in_sync = !GST_BASE_PARSE_LOST_SYNC (parse); @@ -355,8 +355,8 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse, } /* 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)) { + if (!gst_dca_parse_parse_header (dcaparse, &r, &size, &rate, &chans, &depth, + &endianness, &num_blocks, &samples_per_block, &terminator)) { *skipsize = 4; goto cleanup; } @@ -364,8 +364,6 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse, GST_LOG_OBJECT (parse, "got frame, sync %08x, size %u, rate %d, channels %d", sync, size, rate, chans); - *framesize = size; - dcaparse->last_sync = sync; parser_draining = GST_BASE_PARSE_DRAINING (parse); @@ -391,41 +389,18 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse, /* ok, got sync now, let's assume constant frame size */ gst_base_parse_set_min_frame_size (parse, size); } else { - /* FIXME: baseparse always seems to hand us buffers of min_frame_size - * bytes, which is unhelpful here */ + /* wait for some more data */ GST_LOG_OBJECT (dcaparse, "next sync out of reach (%" G_GSIZE_FORMAT " < %u)", map.size, size + 16); - /* *skipsize = 0; */ - /* return FALSE; */ + goto cleanup; } } - ret = TRUE; - -cleanup: - gst_buffer_unmap (buf, &map); - return ret; -} - -static GstFlowReturn -gst_dca_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) -{ - GstDcaParse *dcaparse = GST_DCA_PARSE (parse); - GstBuffer *buf = frame->buffer; - GstByteReader r; - guint size, rate, chans, depth, block_size, num_blocks, samples_per_block; - gint endianness; - gboolean terminator; - GstMapInfo map; - - gst_buffer_map (buf, &map, GST_MAP_READ); - gst_byte_reader_init (&r, map.data, map.size); - - if (!gst_dca_parse_parse_header (dcaparse, &r, &size, &rate, &chans, &depth, - &endianness, &num_blocks, &samples_per_block, &terminator)) - goto broken_header; + /* found frame */ + ret = GST_FLOW_OK; + /* metadata handling */ block_size = num_blocks * samples_per_block; if (G_UNLIKELY (dcaparse->rate != rate || dcaparse->channels != chans @@ -453,17 +428,16 @@ gst_dca_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) gst_base_parse_set_frame_rate (parse, rate, block_size, 0, 0); } +cleanup: gst_buffer_unmap (buf, &map); - return GST_FLOW_OK; - -/* ERRORS */ -broken_header: - { - /* this really shouldn't ever happen */ - GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), (NULL)); - gst_buffer_unmap (buf, &map); - return GST_FLOW_ERROR; + + if (ret == GST_FLOW_OK && size <= map.size) { + ret = gst_base_parse_finish_frame (parse, frame, size); + } else { + ret = GST_FLOW_OK; } + + return ret; } static GstCaps * diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 4480b83..06a964e 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -192,10 +192,10 @@ static void gst_flac_parse_get_property (GObject * object, guint prop_id, static gboolean gst_flac_parse_start (GstBaseParse * parse); static gboolean gst_flac_parse_stop (GstBaseParse * parse); -static gboolean gst_flac_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * framesize, gint * skipsize); +static GstFlowReturn gst_flac_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize); static GstFlowReturn gst_flac_parse_parse_frame (GstBaseParse * parse, - GstBaseParseFrame * frame); + GstBaseParseFrame * frame, gint size); static GstFlowReturn gst_flac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame); static gboolean gst_flac_parse_convert (GstBaseParse * parse, @@ -229,9 +229,8 @@ gst_flac_parse_class_init (GstFlacParseClass * klass) baseparse_class->start = GST_DEBUG_FUNCPTR (gst_flac_parse_start); baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_flac_parse_stop); - baseparse_class->check_valid_frame = - GST_DEBUG_FUNCPTR (gst_flac_parse_check_valid_frame); - baseparse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_parse_frame); + baseparse_class->handle_frame = + GST_DEBUG_FUNCPTR (gst_flac_parse_handle_frame); baseparse_class->pre_push_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_frame); baseparse_class->convert = GST_DEBUG_FUNCPTR (gst_flac_parse_convert); @@ -704,17 +703,21 @@ cleanup: return result; } -static gboolean -gst_flac_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +static GstFlowReturn +gst_flac_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize) { GstFlacParse *flacparse = GST_FLAC_PARSE (parse); GstBuffer *buffer = frame->buffer; GstMapInfo map; gboolean result = TRUE; + GstFlowReturn ret = GST_FLOW_OK; + guint framesize; gst_buffer_map (buffer, &map, GST_MAP_READ); + *skipsize = 1; + if (G_UNLIKELY (map.size < 4)) { result = FALSE; goto cleanup; @@ -723,7 +726,7 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) { if (memcmp (map.data, "fLaC", 4) == 0) { GST_DEBUG_OBJECT (flacparse, "fLaC marker found"); - *framesize = 4; + framesize = 4; goto cleanup; } if (map.data[0] == 0xff && (map.data[1] >> 2) == 0x3e) { @@ -744,7 +747,7 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, guint size = 4 + ((map.data[1] << 16) | (map.data[2] << 8) | (map.data[3])); GST_DEBUG_OBJECT (flacparse, "Found metadata block of size %u", size); - *framesize = size; + framesize = size; goto cleanup; } @@ -759,7 +762,7 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, GST_DEBUG_OBJECT (flacparse, "Found sync code"); ret = gst_flac_parse_frame_is_valid (flacparse, frame, &next); if (ret) { - *framesize = next; + framesize = next; goto cleanup; } else { /* If we're at EOS and the frame was not valid, drop it! */ @@ -809,7 +812,21 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, cleanup: gst_buffer_unmap (buffer, &map); - return result; + + if (result) + *skipsize = 0; + + if (result && framesize <= map.size) { + ret = gst_flac_parse_parse_frame (parse, frame, framesize); + if (ret == GST_BASE_PARSE_FLOW_DROPPED) { + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP; + ret = GST_FLOW_OK; + } + if (ret == GST_FLOW_OK) + ret = gst_base_parse_finish_frame (parse, frame, framesize); + } + + return ret; } static gboolean @@ -1166,6 +1183,7 @@ push_headers: res = FALSE; break; } + gst_base_parse_frame_free (&frame); } g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL); g_list_free (flacparse->headers); @@ -1291,27 +1309,28 @@ gst_flac_parse_generate_headers (GstFlacParse * flacparse) } static GstFlowReturn -gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) +gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame, + gint size) { GstFlacParse *flacparse = GST_FLAC_PARSE (parse); - GstBuffer *buffer = frame->buffer; + GstBuffer *buffer = frame->buffer, *sbuffer; GstMapInfo map; GstFlowReturn res = GST_FLOW_ERROR; gst_buffer_map (buffer, &map, GST_MAP_READ); if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) { - GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE; - GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; - GST_BUFFER_OFFSET (buffer) = 0; - GST_BUFFER_OFFSET_END (buffer) = 0; + sbuffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0, size); + GST_BUFFER_TIMESTAMP (sbuffer) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DURATION (sbuffer) = GST_CLOCK_TIME_NONE; + GST_BUFFER_OFFSET (sbuffer) = 0; + GST_BUFFER_OFFSET_END (sbuffer) = 0; /* 32 bits metadata block */ gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4); flacparse->state = GST_FLAC_PARSE_STATE_HEADERS; - flacparse->headers = - g_list_append (flacparse->headers, gst_buffer_ref (buffer)); + flacparse->headers = g_list_append (flacparse->headers, sbuffer); res = GST_BASE_PARSE_FLOW_DROPPED; } else if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) { @@ -1326,21 +1345,23 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) GST_DEBUG_OBJECT (flacparse, "Handling metadata block of type %u", type); + sbuffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0, size); + switch (type) { case 0: /* STREAMINFO */ - if (!gst_flac_parse_handle_streaminfo (flacparse, buffer)) + if (!gst_flac_parse_handle_streaminfo (flacparse, sbuffer)) goto cleanup; break; case 3: /* SEEKTABLE */ - if (!gst_flac_parse_handle_seektable (flacparse, buffer)) + if (!gst_flac_parse_handle_seektable (flacparse, sbuffer)) goto cleanup; break; case 4: /* VORBIS_COMMENT */ - if (!gst_flac_parse_handle_vorbiscomment (flacparse, buffer)) + if (!gst_flac_parse_handle_vorbiscomment (flacparse, sbuffer)) goto cleanup; break; case 6: /* PICTURE */ - if (!gst_flac_parse_handle_picture (flacparse, buffer)) + if (!gst_flac_parse_handle_picture (flacparse, sbuffer)) goto cleanup; break; case 1: /* PADDING */ @@ -1350,13 +1371,12 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) break; } - GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE; - GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; - GST_BUFFER_OFFSET (buffer) = 0; - GST_BUFFER_OFFSET_END (buffer) = 0; + GST_BUFFER_TIMESTAMP (sbuffer) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DURATION (sbuffer) = GST_CLOCK_TIME_NONE; + GST_BUFFER_OFFSET (sbuffer) = 0; + GST_BUFFER_OFFSET_END (sbuffer) = 0; - flacparse->headers = - g_list_append (flacparse->headers, gst_buffer_ref (buffer)); + flacparse->headers = g_list_append (flacparse->headers, sbuffer); if (is_last) { if (!gst_flac_parse_handle_headers (flacparse)) diff --git a/gst/audioparsers/gstmpegaudioparse.c b/gst/audioparsers/gstmpegaudioparse.c index d3dca66..1cc9f64 100644 --- a/gst/audioparsers/gstmpegaudioparse.c +++ b/gst/audioparsers/gstmpegaudioparse.c @@ -91,10 +91,8 @@ static void gst_mpeg_audio_parse_finalize (GObject * object); static gboolean gst_mpeg_audio_parse_start (GstBaseParse * parse); static gboolean gst_mpeg_audio_parse_stop (GstBaseParse * parse); -static gboolean gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * size, gint * skipsize); -static GstFlowReturn gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse, - GstBaseParseFrame * frame); +static GstFlowReturn gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize); static GstFlowReturn gst_mpeg_audio_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame); static gboolean gst_mpeg_audio_parse_convert (GstBaseParse * parse, @@ -103,6 +101,9 @@ static gboolean gst_mpeg_audio_parse_convert (GstBaseParse * parse, static GstCaps *gst_mpeg_audio_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter); +static void gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse * + mp3parse, GstBuffer * buf); + #define gst_mpeg_audio_parse_parent_class parent_class G_DEFINE_TYPE (GstMpegAudioParse, gst_mpeg_audio_parse, GST_TYPE_BASE_PARSE); @@ -156,10 +157,8 @@ gst_mpeg_audio_parse_class_init (GstMpegAudioParseClass * klass) parse_class->start = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_start); parse_class->stop = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_stop); - parse_class->check_valid_frame = - GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_check_valid_frame); - parse_class->parse_frame = - GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_parse_frame); + parse_class->handle_frame = + GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_handle_frame); parse_class->pre_push_frame = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_pre_push_frame); parse_class->convert = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_convert); @@ -485,9 +484,9 @@ gst_mpeg_audio_parse_head_check (GstMpegAudioParse * mp3parse, return TRUE; } -static gboolean -gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, - GstBaseParseFrame * frame, guint * framesize, gint * skipsize) +static GstFlowReturn +gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize) { GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse); GstBuffer *buf = frame->buffer; @@ -500,8 +499,10 @@ gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, gboolean res = FALSE; gst_buffer_map (buf, &map, GST_MAP_READ); - if (G_UNLIKELY (map.size < 6)) + if (G_UNLIKELY (map.size < 6)) { + *skipsize = 1; goto cleanup; + } gst_byte_reader_init (&reader, map.data, map.size); @@ -566,12 +567,67 @@ gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, /* restore default minimum */ gst_base_parse_set_min_frame_size (parse, MIN_FRAME_SIZE); - *framesize = bpf; res = TRUE; + /* metadata handling */ + if (G_UNLIKELY (caps_change)) { + GstCaps *caps = gst_caps_new_simple ("audio/mpeg", + "mpegversion", G_TYPE_INT, 1, + "mpegaudioversion", G_TYPE_INT, version, + "layer", G_TYPE_INT, layer, + "rate", G_TYPE_INT, rate, + "channels", G_TYPE_INT, channels, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); + gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); + gst_caps_unref (caps); + + mp3parse->rate = rate; + mp3parse->channels = channels; + mp3parse->layer = layer; + mp3parse->version = version; + + /* see http://www.codeproject.com/audio/MPEGAudioInfo.asp */ + if (mp3parse->layer == 1) + mp3parse->spf = 384; + else if (mp3parse->layer == 2) + mp3parse->spf = 1152; + else if (mp3parse->version == 1) { + mp3parse->spf = 1152; + } else { + /* MPEG-2 or "2.5" */ + mp3parse->spf = 576; + } + + /* lead_in: + * We start pushing 9 frames earlier (29 frames for MPEG2) than + * segment start to be able to decode the first frame we want. + * 9 (29) frames are the theoretical maximum of frames that contain + * data for the current frame (bit reservoir). + * + * lead_out: + * Some mp3 streams have an offset in the timestamps, for which we have to + * push the frame *after* the end position in order for the decoder to be + * able to decode everything up until the segment.stop position. */ + gst_base_parse_set_frame_rate (parse, mp3parse->rate, mp3parse->spf, + (version == 1) ? 10 : 30, 2); + } + + mp3parse->hdr_bitrate = bitrate; + + /* For first frame; check for seek tables and output a codec tag */ + gst_mpeg_audio_parse_handle_first_frame (mp3parse, buf); + + /* store some frame info for later processing */ + mp3parse->last_crc = crc; + mp3parse->last_mode = mode; + cleanup: gst_buffer_unmap (buf, &map); - return res; + + if (res && bpf <= map.size) { + return gst_base_parse_finish_frame (parse, frame, bpf); + } + + return GST_FLOW_OK; } static void @@ -977,94 +1033,6 @@ cleanup: gst_buffer_unmap (buf, &map); } -static GstFlowReturn -gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse, - GstBaseParseFrame * frame) -{ - GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse); - GstBuffer *buf = frame->buffer; - GstMapInfo map; - guint bitrate, layer, rate, channels, version, mode, crc; - - gst_buffer_map (buf, &map, GST_MAP_READ); - if (G_UNLIKELY (map.size < 4)) - goto short_buffer; - - if (!mp3_type_frame_length_from_header (mp3parse, - GST_READ_UINT32_BE (map.data), - &version, &layer, &channels, &bitrate, &rate, &mode, &crc)) - goto broken_header; - - if (G_UNLIKELY (channels != mp3parse->channels || rate != mp3parse->rate || - layer != mp3parse->layer || version != mp3parse->version)) { - GstCaps *caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, - "mpegaudioversion", G_TYPE_INT, version, - "layer", G_TYPE_INT, layer, - "rate", G_TYPE_INT, rate, - "channels", G_TYPE_INT, channels, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); - gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); - gst_caps_unref (caps); - - mp3parse->rate = rate; - mp3parse->channels = channels; - mp3parse->layer = layer; - mp3parse->version = version; - - /* see http://www.codeproject.com/audio/MPEGAudioInfo.asp */ - if (mp3parse->layer == 1) - mp3parse->spf = 384; - else if (mp3parse->layer == 2) - mp3parse->spf = 1152; - else if (mp3parse->version == 1) { - mp3parse->spf = 1152; - } else { - /* MPEG-2 or "2.5" */ - mp3parse->spf = 576; - } - - /* lead_in: - * We start pushing 9 frames earlier (29 frames for MPEG2) than - * segment start to be able to decode the first frame we want. - * 9 (29) frames are the theoretical maximum of frames that contain - * data for the current frame (bit reservoir). - * - * lead_out: - * Some mp3 streams have an offset in the timestamps, for which we have to - * push the frame *after* the end position in order for the decoder to be - * able to decode everything up until the segment.stop position. */ - gst_base_parse_set_frame_rate (parse, mp3parse->rate, mp3parse->spf, - (version == 1) ? 10 : 30, 2); - } - - mp3parse->hdr_bitrate = bitrate; - - /* For first frame; check for seek tables and output a codec tag */ - gst_mpeg_audio_parse_handle_first_frame (mp3parse, buf); - - /* store some frame info for later processing */ - mp3parse->last_crc = crc; - mp3parse->last_mode = mode; - - gst_buffer_unmap (buf, &map); - return GST_FLOW_OK; - -/* ERRORS */ -broken_header: - { - /* this really shouldn't ever happen */ - gst_buffer_unmap (buf, &map); - GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), (NULL)); - return GST_FLOW_ERROR; - } - -short_buffer: - { - gst_buffer_unmap (buf, &map); - return GST_FLOW_ERROR; - } -} - static gboolean gst_mpeg_audio_parse_time_to_bytepos (GstMpegAudioParse * mp3parse, GstClockTime ts, gint64 * bytepos) -- 2.7.4