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,
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);
}
/**
* 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");
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");
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),
/* 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");
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),
}
}
- 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;
}
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,
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);
}
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;
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,
}
/* 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))
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;
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 {
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);
/* 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
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
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);
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);
}
*
* 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;
goto done;
}
+ *skipsize = 1;
/* Does this look like a possible frame header candidate? */
if ((map.data[0] & 0x83) == 0) {
/* Yep. Retrieve the frame size */
* perform this check)
*/
if (fsize) {
- gboolean found = FALSE;
-
+ *skipsize = 0;
/* in sync, no further check */
if (!GST_BASE_PARSE_LOST_SYNC (parse)) {
found = TRUE;
} 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.
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);
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,
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;
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);
}
/* 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;
}
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);
/* 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
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 *
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,
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);
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;
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) {
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;
}
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! */
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
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);
}
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) {
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 */
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))
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,
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);
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);
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;
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);
/* 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
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)