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, static GstCaps *gst_aac_parse_sink_getcaps (GstBaseParse * parse,
GstCaps * filter); GstCaps * filter);
static gboolean gst_aac_parse_check_valid_frame (GstBaseParse * parse, static GstFlowReturn gst_aac_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * size, gint * skipsize); GstBaseParseFrame * frame, gint * skipsize);
static GstFlowReturn gst_aac_parse_parse_frame (GstBaseParse * parse,
GstBaseParseFrame * frame);
gboolean gst_aac_parse_convert (GstBaseParse * parse, gboolean gst_aac_parse_convert (GstBaseParse * parse,
GstFormat src_format, 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->stop = GST_DEBUG_FUNCPTR (gst_aac_parse_stop);
parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_aac_parse_sink_setcaps); 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->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->handle_frame = GST_DEBUG_FUNCPTR (gst_aac_parse_handle_frame);
parse_class->check_valid_frame =
GST_DEBUG_FUNCPTR (gst_aac_parse_check_valid_frame);
} }
@ -900,84 +895,11 @@ gst_aac_parse_detect_stream (GstAacParse * aacparse,
/** /**
* gst_aac_parse_check_valid_frame: * gst_aac_parse_check_valid_frame:
* @parse: #GstBaseParse. * @parse: #GstBaseParse.
* @buffer: #GstBuffer. * @frame: #GstBaseParseFrame.
* @framesize: If the buffer contains a valid frame, its size will be put here
* @skipsize: How much data parent class should skip in order to find the * @skipsize: How much data parent class should skip in order to find the
* frame header. * frame header.
* *
* Implementation of "check_valid_frame" vmethod in #GstBaseParse class. * Implementation of "handle_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.
* *
* Also determines frame overhead. * Also determines frame overhead.
* ADTS streams have a 7 byte header in each frame. MP4 and ADIF streams don't have * ADTS streams have a 7 byte header in each frame. MP4 and ADIF streams don't have
@ -992,47 +914,92 @@ gst_aac_parse_check_valid_frame (GstBaseParse * parse,
* bits, which should still not be significant enough to warrant the * bits, which should still not be significant enough to warrant the
* additional parsing through the headers * additional parsing through the headers
* *
* Returns: GST_FLOW_OK if frame was successfully parsed and can be pushed * Returns: a #GstFlowReturn.
* forward. Otherwise appropriate error is returned.
*/ */
static 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; GstMapInfo map;
GstAacParse *aacparse;
gboolean ret = FALSE;
gboolean lost_sync;
GstBuffer *buffer;
guint framesize;
gint rate, channels;
aacparse = GST_AAC_PARSE (parse); aacparse = GST_AAC_PARSE (parse);
buffer = frame->buffer; 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) { if (aacparse->header_type == DSPAAC_HEADER_ADTS) {
/* see above */ /* see above */
frame->overhead = 7; frame->overhead = 7;
gst_buffer_map (buffer, &map, GST_MAP_READ);
gst_aac_parse_parse_adts_header (aacparse, map.data, gst_aac_parse_parse_adts_header (aacparse, map.data,
&rate, &channels, NULL, NULL); &rate, &channels, NULL, NULL);
gst_buffer_unmap (buffer, &map);
GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels); GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels);
if (G_UNLIKELY (rate != aacparse->sample_rate if (G_UNLIKELY (rate != aacparse->sample_rate
|| channels != aacparse->channels)) { || channels != aacparse->channels)) {
GstCaps *sinkcaps;
aacparse->sample_rate = rate; aacparse->sample_rate = rate;
aacparse->channels = channels; aacparse->channels = channels;
if ((sinkcaps = GST_DEBUG_OBJECT (aacparse, "here");
gst_pad_get_current_caps (GST_BASE_PARSE (aacparse)->sinkpad))) {
if (!gst_aac_parse_set_src_caps (aacparse, sinkcaps)) { if (!gst_aac_parse_set_src_caps (aacparse, NULL)) {
/* If linking fails, we need to return appropriate error */ /* If linking fails, we need to return appropriate error */
ret = GST_FLOW_NOT_LINKED; ret = GST_FLOW_NOT_LINKED;
} }
gst_caps_unref (sinkcaps);
}
gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
aacparse->sample_rate, aacparse->frame_samples, 2, 2); aacparse->sample_rate, aacparse->frame_samples, 2, 2);
@ -1043,7 +1010,6 @@ gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
/* see above */ /* see above */
frame->overhead = 3; frame->overhead = 3;
gst_buffer_map (buffer, &map, GST_MAP_READ);
if (!gst_aac_parse_read_loas_config (aacparse, map.data, map.size, &rate, if (!gst_aac_parse_read_loas_config (aacparse, map.data, map.size, &rate,
&channels, NULL)) { &channels, NULL)) {
GST_WARNING_OBJECT (aacparse, "Error reading LOAS config"); GST_WARNING_OBJECT (aacparse, "Error reading LOAS config");
@ -1055,30 +1021,40 @@ gst_aac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
GST_INFO_OBJECT (aacparse, "New LOAS config: %d Hz, %d channels", rate, GST_INFO_OBJECT (aacparse, "New LOAS config: %d Hz, %d channels", rate,
channels); channels);
} }
gst_buffer_unmap (buffer, &map);
/* We want to set caps both at start, and when rate/channels change. /* 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 Since only some LOAS frames have that info, we may receive frames
before knowing about rate/channels. */ before knowing about rate/channels. */
if (setcaps if (setcaps
|| !gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (aacparse))) { || !gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (aacparse))) {
GstCaps *sinkcaps; if (!gst_aac_parse_set_src_caps (aacparse, NULL)) {
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 */ /* If linking fails, we need to return appropriate error */
ret = GST_FLOW_NOT_LINKED; ret = GST_FLOW_NOT_LINKED;
} }
gst_caps_unref (sinkcaps);
}
gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse), gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
aacparse->sample_rate, aacparse->frame_samples, 2, 2); aacparse->sample_rate, aacparse->frame_samples, 2, 2);
} }
} }
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_start (GstBaseParse * parse);
static gboolean gst_ac3_parse_stop (GstBaseParse * parse); static gboolean gst_ac3_parse_stop (GstBaseParse * parse);
static gboolean gst_ac3_parse_check_valid_frame (GstBaseParse * parse, static GstFlowReturn gst_ac3_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * size, gint * skipsize); GstBaseParseFrame * frame, gint * skipsize);
static GstFlowReturn gst_ac3_parse_parse_frame (GstBaseParse * parse,
GstBaseParseFrame * frame);
static gboolean gst_ac3_parse_src_event (GstBaseParse * parse, static gboolean gst_ac3_parse_src_event (GstBaseParse * parse,
GstEvent * event); GstEvent * event);
static GstCaps *gst_ac3_parse_get_sink_caps (GstBaseParse * parse, 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->start = GST_DEBUG_FUNCPTR (gst_ac3_parse_start);
parse_class->stop = GST_DEBUG_FUNCPTR (gst_ac3_parse_stop); parse_class->stop = GST_DEBUG_FUNCPTR (gst_ac3_parse_stop);
parse_class->check_valid_frame = parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_ac3_parse_handle_frame);
GST_DEBUG_FUNCPTR (gst_ac3_parse_check_valid_frame);
parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_ac3_parse_parse_frame);
parse_class->src_event = GST_DEBUG_FUNCPTR (gst_ac3_parse_src_event); 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); parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_ac3_parse_get_sink_caps);
} }
@ -481,9 +477,9 @@ cleanup:
return ret; return ret;
} }
static gboolean static GstFlowReturn
gst_ac3_parse_check_valid_frame (GstBaseParse * parse, gst_ac3_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * framesize, gint * skipsize) GstBaseParseFrame * frame, gint * skipsize)
{ {
GstAc3Parse *ac3parse = GST_AC3_PARSE (parse); GstAc3Parse *ac3parse = GST_AC3_PARSE (parse);
GstBuffer *buf = frame->buffer; GstBuffer *buf = frame->buffer;
@ -491,14 +487,20 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse,
gint off; gint off;
gboolean lost_sync, draining, eac, more = FALSE; gboolean lost_sync, draining, eac, more = FALSE;
guint frmsiz, blocks, sid; guint frmsiz, blocks, sid;
guint rate, chans;
gboolean update_rate = FALSE;
gint framesize = 0;
gint have_blocks = 0; gint have_blocks = 0;
GstMapInfo map; GstMapInfo map;
gboolean ret = FALSE; gboolean ret = FALSE;
GstFlowReturn res = GST_FLOW_OK;
gst_buffer_map (buf, &map, GST_MAP_READ); gst_buffer_map (buf, &map, GST_MAP_READ);
if (G_UNLIKELY (map.size < 6)) if (G_UNLIKELY (map.size < 6)) {
*skipsize = 1;
goto cleanup; goto cleanup;
}
gst_byte_reader_init (&reader, map.data, map.size); gst_byte_reader_init (&reader, map.data, map.size);
off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000, 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 */ /* 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)) { &blocks, &sid, &eac)) {
*skipsize = off + 2; *skipsize = off + 2;
goto cleanup; 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) == if (G_UNLIKELY (g_atomic_int_get (&ac3parse->align) ==
GST_AC3_PARSE_ALIGN_NONE)) GST_AC3_PARSE_ALIGN_NONE))
@ -550,21 +555,21 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse,
goto cleanup; goto cleanup;
} }
*framesize = 0; framesize = 0;
/* Loop till we have 6 blocks per substream */ /* Loop till we have 6 blocks per substream */
for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) { for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) {
/* Loop till we get one frame from each substream */ /* Loop till we get one frame from each substream */
do { do {
*framesize += frmsiz; framesize += frmsiz;
if (!gst_byte_reader_skip (&reader, frmsiz) if (!gst_byte_reader_skip (&reader, frmsiz)
|| map.size < (*framesize + 6)) { || map.size < (framesize + 6)) {
more = TRUE; more = TRUE;
break; 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)) { NULL, NULL, NULL, &sid, &eac)) {
*skipsize = off + 2; *skipsize = off + 2;
goto cleanup; goto cleanup;
@ -584,7 +589,7 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse,
if (more || !gst_byte_reader_skip (&reader, frmsiz) || if (more || !gst_byte_reader_skip (&reader, frmsiz) ||
!gst_byte_reader_get_uint16_be (&reader, &word)) { !gst_byte_reader_get_uint16_be (&reader, &word)) {
GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data"); 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; *skipsize = 0;
goto cleanup; goto cleanup;
} else { } else {
@ -594,34 +599,16 @@ gst_ac3_parse_check_valid_frame (GstBaseParse * parse,
goto cleanup; goto cleanup;
} else { } else {
/* ok, got sync now, let's assume constant frame size */ /* 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; ret = TRUE;
cleanup: /* arrange for metadata setup */
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);
if (G_UNLIKELY (sid)) { if (G_UNLIKELY (sid)) {
/* dependent frame, no need to (ac)count for or consider further */ /* dependent frame, no need to (ac)count for or consider further */
GST_LOG_OBJECT (parse, "sid: %d", sid); 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 */ /* occupies same time space as previous base frame */
if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf))) if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf)))
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)) if (G_LIKELY (ac3parse->sample_rate > 0))
return GST_FLOW_OK; goto cleanup;
} }
if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans 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)) if (G_UNLIKELY (update_rate))
gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2); gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2);
return GST_FLOW_OK; cleanup:
gst_buffer_unmap (buf, &map);
/* ERRORS */ if (ret && framesize <= map.size) {
broken_header: res = gst_base_parse_finish_frame (parse, frame, framesize);
{
/* this really shouldn't ever happen */
GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), (NULL));
return GST_FLOW_ERROR;
} }
return res;
} }
static gboolean 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, static GstCaps *gst_amr_parse_sink_getcaps (GstBaseParse * parse,
GstCaps * filter); GstCaps * filter);
static gboolean gst_amr_parse_check_valid_frame (GstBaseParse * parse, static GstFlowReturn gst_amr_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * framesize, gint * skipsize); GstBaseParseFrame * frame, gint * skipsize);
static GstFlowReturn gst_amr_parse_parse_frame (GstBaseParse * parse,
GstBaseParseFrame * frame);
G_DEFINE_TYPE (GstAmrParse, gst_amr_parse, GST_TYPE_BASE_PARSE); 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->stop = GST_DEBUG_FUNCPTR (gst_amr_parse_stop);
parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_amr_parse_sink_setcaps); 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->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->handle_frame = GST_DEBUG_FUNCPTR (gst_amr_parse_handle_frame);
parse_class->check_valid_frame =
GST_DEBUG_FUNCPTR (gst_amr_parse_check_valid_frame);
} }
@ -254,15 +249,16 @@ gst_amr_parse_parse_header (GstAmrParse * amrparse,
* *
* Returns: TRUE if the given data contains valid frame. * Returns: TRUE if the given data contains valid frame.
*/ */
static gboolean static GstFlowReturn
gst_amr_parse_check_valid_frame (GstBaseParse * parse, gst_amr_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * framesize, gint * skipsize) GstBaseParseFrame * frame, gint * skipsize)
{ {
GstBuffer *buffer; GstBuffer *buffer;
GstMapInfo map; GstMapInfo map;
gint fsize, mode, dsize; gint fsize = 0, mode, dsize;
GstAmrParse *amrparse; GstAmrParse *amrparse;
gboolean ret = FALSE; GstFlowReturn ret = GST_FLOW_OK;
gboolean found = FALSE;
amrparse = GST_AMR_PARSE (parse); amrparse = GST_AMR_PARSE (parse);
buffer = frame->buffer; buffer = frame->buffer;
@ -285,6 +281,7 @@ gst_amr_parse_check_valid_frame (GstBaseParse * parse,
goto done; goto done;
} }
*skipsize = 1;
/* Does this look like a possible frame header candidate? */ /* Does this look like a possible frame header candidate? */
if ((map.data[0] & 0x83) == 0) { if ((map.data[0] & 0x83) == 0) {
/* Yep. Retrieve the frame size */ /* Yep. Retrieve the frame size */
@ -299,8 +296,7 @@ gst_amr_parse_check_valid_frame (GstBaseParse * parse,
* perform this check) * perform this check)
*/ */
if (fsize) { if (fsize) {
gboolean found = FALSE; *skipsize = 0;
/* in sync, no further check */ /* in sync, no further check */
if (!GST_BASE_PARSE_LOST_SYNC (parse)) { if (!GST_BASE_PARSE_LOST_SYNC (parse)) {
found = TRUE; found = TRUE;
@ -311,42 +307,20 @@ gst_amr_parse_check_valid_frame (GstBaseParse * parse,
} else if (GST_BASE_PARSE_DRAINING (parse)) { } else if (GST_BASE_PARSE_DRAINING (parse)) {
/* not enough, but draining, so ok */ /* not enough, but draining, so ok */
found = TRUE; 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: done:
gst_buffer_unmap (buffer, &map); gst_buffer_unmap (buffer, &map);
if (found && fsize <= map.size) {
ret = gst_base_parse_finish_frame (parse, frame, fsize);
}
return ret; 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: * gst_amr_parse_start:
* @parse: #GstBaseParse. * @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_start (GstBaseParse * parse);
static gboolean gst_dca_parse_stop (GstBaseParse * parse); static gboolean gst_dca_parse_stop (GstBaseParse * parse);
static gboolean gst_dca_parse_check_valid_frame (GstBaseParse * parse, static GstFlowReturn gst_dca_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * size, gint * skipsize); GstBaseParseFrame * frame, gint * skipsize);
static GstFlowReturn gst_dca_parse_parse_frame (GstBaseParse * parse,
GstBaseParseFrame * frame);
static GstCaps *gst_dca_parse_get_sink_caps (GstBaseParse * parse, static GstCaps *gst_dca_parse_get_sink_caps (GstBaseParse * parse,
GstCaps * filter); 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->start = GST_DEBUG_FUNCPTR (gst_dca_parse_start);
parse_class->stop = GST_DEBUG_FUNCPTR (gst_dca_parse_stop); parse_class->stop = GST_DEBUG_FUNCPTR (gst_dca_parse_stop);
parse_class->check_valid_frame = parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_dca_parse_handle_frame);
GST_DEBUG_FUNCPTR (gst_dca_parse_check_valid_frame);
parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_dca_parse_parse_frame);
parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_dca_parse_get_sink_caps); parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_dca_parse_get_sink_caps);
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
@ -305,9 +301,9 @@ gst_dca_parse_find_sync (GstDcaParse * dcaparse, GstByteReader * reader,
return best_offset; return best_offset;
} }
static gboolean static GstFlowReturn
gst_dca_parse_check_valid_frame (GstBaseParse * parse, gst_dca_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * framesize, gint * skipsize) GstBaseParseFrame * frame, gint * skipsize)
{ {
GstDcaParse *dcaparse = GST_DCA_PARSE (parse); GstDcaParse *dcaparse = GST_DCA_PARSE (parse);
GstBuffer *buf = frame->buffer; GstBuffer *buf = frame->buffer;
@ -316,15 +312,19 @@ gst_dca_parse_check_valid_frame (GstBaseParse * parse,
gboolean parser_in_sync; gboolean parser_in_sync;
gboolean terminator; gboolean terminator;
guint32 sync = 0; 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; gint off = -1;
GstMapInfo map; GstMapInfo map;
gboolean ret = FALSE; GstFlowReturn ret = GST_FLOW_EOS;
gst_buffer_map (buf, &map, GST_MAP_READ); gst_buffer_map (buf, &map, GST_MAP_READ);
if (G_UNLIKELY (map.size < 16)) if (G_UNLIKELY (map.size < 16)) {
*skipsize = 1;
goto cleanup; goto cleanup;
}
parser_in_sync = !GST_BASE_PARSE_LOST_SYNC (parse); 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 */ /* make sure the values in the frame header look sane */
if (!gst_dca_parse_parse_header (dcaparse, &r, &size, &rate, &chans, NULL, if (!gst_dca_parse_parse_header (dcaparse, &r, &size, &rate, &chans, &depth,
NULL, &num_blocks, &samples_per_block, &terminator)) { &endianness, &num_blocks, &samples_per_block, &terminator)) {
*skipsize = 4; *skipsize = 4;
goto cleanup; 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", GST_LOG_OBJECT (parse, "got frame, sync %08x, size %u, rate %d, channels %d",
sync, size, rate, chans); sync, size, rate, chans);
*framesize = size;
dcaparse->last_sync = sync; dcaparse->last_sync = sync;
parser_draining = GST_BASE_PARSE_DRAINING (parse); 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 */ /* ok, got sync now, let's assume constant frame size */
gst_base_parse_set_min_frame_size (parse, size); gst_base_parse_set_min_frame_size (parse, size);
} else { } else {
/* FIXME: baseparse always seems to hand us buffers of min_frame_size /* wait for some more data */
* bytes, which is unhelpful here */
GST_LOG_OBJECT (dcaparse, GST_LOG_OBJECT (dcaparse,
"next sync out of reach (%" G_GSIZE_FORMAT " < %u)", map.size, "next sync out of reach (%" G_GSIZE_FORMAT " < %u)", map.size,
size + 16); size + 16);
/* *skipsize = 0; */ goto cleanup;
/* return FALSE; */
} }
} }
ret = TRUE; /* found frame */
ret = GST_FLOW_OK;
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;
/* metadata handling */
block_size = num_blocks * samples_per_block; block_size = num_blocks * samples_per_block;
if (G_UNLIKELY (dcaparse->rate != rate || dcaparse->channels != chans 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); gst_base_parse_set_frame_rate (parse, rate, block_size, 0, 0);
} }
cleanup:
gst_buffer_unmap (buf, &map); gst_buffer_unmap (buf, &map);
return GST_FLOW_OK;
/* ERRORS */ if (ret == GST_FLOW_OK && size <= map.size) {
broken_header: ret = gst_base_parse_finish_frame (parse, frame, size);
{ } else {
/* this really shouldn't ever happen */ ret = GST_FLOW_OK;
GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), (NULL));
gst_buffer_unmap (buf, &map);
return GST_FLOW_ERROR;
} }
return ret;
} }
static GstCaps * 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_start (GstBaseParse * parse);
static gboolean gst_flac_parse_stop (GstBaseParse * parse); static gboolean gst_flac_parse_stop (GstBaseParse * parse);
static gboolean gst_flac_parse_check_valid_frame (GstBaseParse * parse, static GstFlowReturn gst_flac_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * framesize, gint * skipsize); GstBaseParseFrame * frame, gint * skipsize);
static GstFlowReturn gst_flac_parse_parse_frame (GstBaseParse * parse, 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, static GstFlowReturn gst_flac_parse_pre_push_frame (GstBaseParse * parse,
GstBaseParseFrame * frame); GstBaseParseFrame * frame);
static gboolean gst_flac_parse_convert (GstBaseParse * parse, 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->start = GST_DEBUG_FUNCPTR (gst_flac_parse_start);
baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_flac_parse_stop); baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_flac_parse_stop);
baseparse_class->check_valid_frame = baseparse_class->handle_frame =
GST_DEBUG_FUNCPTR (gst_flac_parse_check_valid_frame); GST_DEBUG_FUNCPTR (gst_flac_parse_handle_frame);
baseparse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_parse_frame);
baseparse_class->pre_push_frame = baseparse_class->pre_push_frame =
GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_frame); GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_frame);
baseparse_class->convert = GST_DEBUG_FUNCPTR (gst_flac_parse_convert); baseparse_class->convert = GST_DEBUG_FUNCPTR (gst_flac_parse_convert);
@ -704,17 +703,21 @@ cleanup:
return result; return result;
} }
static gboolean static GstFlowReturn
gst_flac_parse_check_valid_frame (GstBaseParse * parse, gst_flac_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * framesize, gint * skipsize) GstBaseParseFrame * frame, gint * skipsize)
{ {
GstFlacParse *flacparse = GST_FLAC_PARSE (parse); GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
GstBuffer *buffer = frame->buffer; GstBuffer *buffer = frame->buffer;
GstMapInfo map; GstMapInfo map;
gboolean result = TRUE; gboolean result = TRUE;
GstFlowReturn ret = GST_FLOW_OK;
guint framesize;
gst_buffer_map (buffer, &map, GST_MAP_READ); gst_buffer_map (buffer, &map, GST_MAP_READ);
*skipsize = 1;
if (G_UNLIKELY (map.size < 4)) { if (G_UNLIKELY (map.size < 4)) {
result = FALSE; result = FALSE;
goto cleanup; goto cleanup;
@ -723,7 +726,7 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse,
if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) { if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) {
if (memcmp (map.data, "fLaC", 4) == 0) { if (memcmp (map.data, "fLaC", 4) == 0) {
GST_DEBUG_OBJECT (flacparse, "fLaC marker found"); GST_DEBUG_OBJECT (flacparse, "fLaC marker found");
*framesize = 4; framesize = 4;
goto cleanup; goto cleanup;
} }
if (map.data[0] == 0xff && (map.data[1] >> 2) == 0x3e) { 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])); 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); GST_DEBUG_OBJECT (flacparse, "Found metadata block of size %u", size);
*framesize = size; framesize = size;
goto cleanup; goto cleanup;
} }
@ -759,7 +762,7 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse,
GST_DEBUG_OBJECT (flacparse, "Found sync code"); GST_DEBUG_OBJECT (flacparse, "Found sync code");
ret = gst_flac_parse_frame_is_valid (flacparse, frame, &next); ret = gst_flac_parse_frame_is_valid (flacparse, frame, &next);
if (ret) { if (ret) {
*framesize = next; framesize = next;
goto cleanup; goto cleanup;
} else { } else {
/* If we're at EOS and the frame was not valid, drop it! */ /* 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: cleanup:
gst_buffer_unmap (buffer, &map); 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 static gboolean
@ -1166,6 +1183,7 @@ push_headers:
res = FALSE; res = FALSE;
break; break;
} }
gst_base_parse_frame_free (&frame);
} }
g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL); g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL);
g_list_free (flacparse->headers); g_list_free (flacparse->headers);
@ -1291,27 +1309,28 @@ gst_flac_parse_generate_headers (GstFlacParse * flacparse)
} }
static GstFlowReturn 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); GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
GstBuffer *buffer = frame->buffer; GstBuffer *buffer = frame->buffer, *sbuffer;
GstMapInfo map; GstMapInfo map;
GstFlowReturn res = GST_FLOW_ERROR; GstFlowReturn res = GST_FLOW_ERROR;
gst_buffer_map (buffer, &map, GST_MAP_READ); gst_buffer_map (buffer, &map, GST_MAP_READ);
if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) { if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) {
GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE; sbuffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0, size);
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_TIMESTAMP (sbuffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buffer) = 0; GST_BUFFER_DURATION (sbuffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET_END (buffer) = 0; GST_BUFFER_OFFSET (sbuffer) = 0;
GST_BUFFER_OFFSET_END (sbuffer) = 0;
/* 32 bits metadata block */ /* 32 bits metadata block */
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4); gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4);
flacparse->state = GST_FLAC_PARSE_STATE_HEADERS; flacparse->state = GST_FLAC_PARSE_STATE_HEADERS;
flacparse->headers = flacparse->headers = g_list_append (flacparse->headers, sbuffer);
g_list_append (flacparse->headers, gst_buffer_ref (buffer));
res = GST_BASE_PARSE_FLOW_DROPPED; res = GST_BASE_PARSE_FLOW_DROPPED;
} else if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) { } 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); 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) { switch (type) {
case 0: /* STREAMINFO */ case 0: /* STREAMINFO */
if (!gst_flac_parse_handle_streaminfo (flacparse, buffer)) if (!gst_flac_parse_handle_streaminfo (flacparse, sbuffer))
goto cleanup; goto cleanup;
break; break;
case 3: /* SEEKTABLE */ case 3: /* SEEKTABLE */
if (!gst_flac_parse_handle_seektable (flacparse, buffer)) if (!gst_flac_parse_handle_seektable (flacparse, sbuffer))
goto cleanup; goto cleanup;
break; break;
case 4: /* VORBIS_COMMENT */ case 4: /* VORBIS_COMMENT */
if (!gst_flac_parse_handle_vorbiscomment (flacparse, buffer)) if (!gst_flac_parse_handle_vorbiscomment (flacparse, sbuffer))
goto cleanup; goto cleanup;
break; break;
case 6: /* PICTURE */ case 6: /* PICTURE */
if (!gst_flac_parse_handle_picture (flacparse, buffer)) if (!gst_flac_parse_handle_picture (flacparse, sbuffer))
goto cleanup; goto cleanup;
break; break;
case 1: /* PADDING */ case 1: /* PADDING */
@ -1350,13 +1371,12 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
break; break;
} }
GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_TIMESTAMP (sbuffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (sbuffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buffer) = 0; GST_BUFFER_OFFSET (sbuffer) = 0;
GST_BUFFER_OFFSET_END (buffer) = 0; GST_BUFFER_OFFSET_END (sbuffer) = 0;
flacparse->headers = flacparse->headers = g_list_append (flacparse->headers, sbuffer);
g_list_append (flacparse->headers, gst_buffer_ref (buffer));
if (is_last) { if (is_last) {
if (!gst_flac_parse_handle_headers (flacparse)) 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_start (GstBaseParse * parse);
static gboolean gst_mpeg_audio_parse_stop (GstBaseParse * parse); static gboolean gst_mpeg_audio_parse_stop (GstBaseParse * parse);
static gboolean gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, static GstFlowReturn gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * size, gint * skipsize); GstBaseParseFrame * frame, gint * skipsize);
static GstFlowReturn gst_mpeg_audio_parse_parse_frame (GstBaseParse * parse,
GstBaseParseFrame * frame);
static GstFlowReturn gst_mpeg_audio_parse_pre_push_frame (GstBaseParse * parse, static GstFlowReturn gst_mpeg_audio_parse_pre_push_frame (GstBaseParse * parse,
GstBaseParseFrame * frame); GstBaseParseFrame * frame);
static gboolean gst_mpeg_audio_parse_convert (GstBaseParse * parse, 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, static GstCaps *gst_mpeg_audio_parse_get_sink_caps (GstBaseParse * parse,
GstCaps * filter); GstCaps * filter);
static void gst_mpeg_audio_parse_handle_first_frame (GstMpegAudioParse *
mp3parse, GstBuffer * buf);
#define gst_mpeg_audio_parse_parent_class parent_class #define gst_mpeg_audio_parse_parent_class parent_class
G_DEFINE_TYPE (GstMpegAudioParse, gst_mpeg_audio_parse, GST_TYPE_BASE_PARSE); 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->start = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_start);
parse_class->stop = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_stop); parse_class->stop = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_stop);
parse_class->check_valid_frame = parse_class->handle_frame =
GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_check_valid_frame); GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_handle_frame);
parse_class->parse_frame =
GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_parse_frame);
parse_class->pre_push_frame = parse_class->pre_push_frame =
GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_pre_push_frame); GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_pre_push_frame);
parse_class->convert = GST_DEBUG_FUNCPTR (gst_mpeg_audio_parse_convert); 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; return TRUE;
} }
static gboolean static GstFlowReturn
gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse, gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * framesize, gint * skipsize) GstBaseParseFrame * frame, gint * skipsize)
{ {
GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse); GstMpegAudioParse *mp3parse = GST_MPEG_AUDIO_PARSE (parse);
GstBuffer *buf = frame->buffer; GstBuffer *buf = frame->buffer;
@ -500,8 +499,10 @@ gst_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse,
gboolean res = FALSE; gboolean res = FALSE;
gst_buffer_map (buf, &map, GST_MAP_READ); gst_buffer_map (buf, &map, GST_MAP_READ);
if (G_UNLIKELY (map.size < 6)) if (G_UNLIKELY (map.size < 6)) {
*skipsize = 1;
goto cleanup; goto cleanup;
}
gst_byte_reader_init (&reader, map.data, map.size); 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 */ /* restore default minimum */
gst_base_parse_set_min_frame_size (parse, MIN_FRAME_SIZE); gst_base_parse_set_min_frame_size (parse, MIN_FRAME_SIZE);
*framesize = bpf;
res = TRUE; 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: cleanup:
gst_buffer_unmap (buf, &map); 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 static void
@ -977,94 +1033,6 @@ cleanup:
gst_buffer_unmap (buf, &map); 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 static gboolean
gst_mpeg_audio_parse_time_to_bytepos (GstMpegAudioParse * mp3parse, gst_mpeg_audio_parse_time_to_bytepos (GstMpegAudioParse * mp3parse,
GstClockTime ts, gint64 * bytepos) GstClockTime ts, gint64 * bytepos)