audioparsers: adjust to modified baseparse API

This commit is contained in:
Mark Nauwelaerts 2012-02-09 13:41:53 +01:00
parent e3b5a2e40d
commit 1ae32656ae
6 changed files with 287 additions and 389 deletions

View file

@ -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,84 +895,11 @@ 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.
*
* Returns: TRUE if buffer contains a valid frame.
*/
static gboolean
gst_aac_parse_check_valid_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
{
GstMapInfo map;
GstAacParse *aacparse;
gboolean ret = FALSE;
gboolean lost_sync;
GstBuffer *buffer;
aacparse = GST_AAC_PARSE (parse);
buffer = frame->buffer;
gst_buffer_map (buffer, &map, GST_MAP_READ);
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;
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);
} 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);
if (!ret) {
GST_DEBUG ("buffer didn't contain valid frame");
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
needed_data);
}
} else if (aacparse->header_type == DSPAAC_HEADER_LOAS) {
guint needed_data = 1024;
ret = gst_aac_parse_check_loas_frame (aacparse, map.data,
map.size, GST_BASE_PARSE_DRAINING (parse), framesize, &needed_data);
if (!ret) {
GST_DEBUG ("buffer didn't contain valid frame");
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
needed_data);
}
} else {
GST_DEBUG ("buffer didn't contain valid frame");
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.
* 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
@ -992,46 +914,91 @@ gst_aac_parse_check_valid_frame (GstBaseParse * parse,
* 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.
* Returns: a #GstFlowReturn.
*/
static GstFlowReturn
gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gst_aac_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, gint * skipsize)
{
GstAacParse *aacparse;
GstBuffer *buffer;
GstFlowReturn ret = GST_FLOW_OK;
gint rate, channels;
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;
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);
} 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);
if (!ret) {
GST_DEBUG ("buffer didn't contain valid frame");
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
needed_data);
}
} else if (aacparse->header_type == DSPAAC_HEADER_LOAS) {
guint needed_data = 1024;
ret = gst_aac_parse_check_loas_frame (aacparse, map.data,
map.size, GST_BASE_PARSE_DRAINING (parse), &framesize, &needed_data);
if (!ret) {
GST_DEBUG ("buffer didn't contain valid frame");
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
needed_data);
}
} else {
GST_DEBUG ("buffer didn't contain valid frame");
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
ADTS_MAX_SIZE);
}
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;
}

View file

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

View file

@ -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);
if (found && fsize <= map.size) {
ret = gst_base_parse_finish_frame (parse, frame, fsize);
}
return ret;
}
/**
* 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;
}
/**
* gst_amr_parse_start:
* @parse: #GstBaseParse.

View file

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

View file

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

View file

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