From adbe2a1b69af3050578701a5717cfe146c06775e Mon Sep 17 00:00:00 2001 From: Julien Moutte Date: Sat, 27 Oct 2007 08:20:59 +0000 Subject: gst/mpeg4videoparse/mpeg4videoparse.*: Improved version not damaging headers using a simple state machine. Original commit message from CVS: 2007-10-27 Julien MOUTTE * gst/mpeg4videoparse/mpeg4videoparse.c: (gst_mpeg4vparse_align), (gst_mpeg4vparse_drain), (gst_mpeg4vparse_chain), (gst_mpeg4vparse_sink_setcaps), (gst_mpeg4vparse_sink_event), (gst_mpeg4vparse_cleanup), (gst_mpeg4vparse_change_state), (gst_mpeg4vparse_dispose), (gst_mpeg4vparse_base_init), (gst_mpeg4vparse_class_init), (gst_mpeg4vparse_init), (plugin_init): * gst/mpeg4videoparse/mpeg4videoparse.h: Improved version not damaging headers using a simple state machine. --- gst/mpeg4videoparse/mpeg4videoparse.c | 106 +++++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 28 deletions(-) (limited to 'gst/mpeg4videoparse/mpeg4videoparse.c') diff --git a/gst/mpeg4videoparse/mpeg4videoparse.c b/gst/mpeg4videoparse/mpeg4videoparse.c index 21be173c..e4dffa31 100644 --- a/gst/mpeg4videoparse/mpeg4videoparse.c +++ b/gst/mpeg4videoparse/mpeg4videoparse.c @@ -51,51 +51,81 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_BOILERPLATE (GstMpeg4VParse, gst_mpeg4vparse, GstElement, GST_TYPE_ELEMENT); -static GstFlowReturn -gst_mpeg4vparse_drain (GstMpeg4VParse * parse) +static void +gst_mpeg4vparse_align (GstMpeg4VParse * parse) { - GstFlowReturn ret = GST_FLOW_OK; - const guint8 *data = NULL; - guint i = 0, available = 0; + guint flushed = 0; + /* Searching for a start code */ while (gst_adapter_available (parse->adapter) >= 4) { /* If we have enough data, ensure we're aligned to a start code */ - data = gst_adapter_peek (parse->adapter, 4); + const guint8 *data = gst_adapter_peek (parse->adapter, 4); + if (data[0] == 0 && data[1] == 0 && data[2] == 1) { GST_LOG_OBJECT (parse, "found start code with type %02X", data[3]); - parse->found_start = TRUE; + parse->state = PARSE_START_FOUND; break; } else { - GST_LOG_OBJECT (parse, "flushing 1 byte"); gst_adapter_flush (parse->adapter, 1); + flushed++; + parse->state = PARSE_NEED_START; } } - if (G_UNLIKELY (!parse->found_start)) { - GST_DEBUG_OBJECT (parse, "start code not found, need more data"); - goto beach; + if (G_UNLIKELY (flushed)) { + GST_LOG_OBJECT (parse, "flushed %u bytes while aligning", flushed); } +} - if (G_UNLIKELY (gst_adapter_available (parse->adapter) < 8)) { - GST_DEBUG_OBJECT (parse, "start code found, need more data to find next"); - goto beach; - } +static GstFlowReturn +gst_mpeg4vparse_drain (GstMpeg4VParse * parse) +{ + GstFlowReturn ret = GST_FLOW_OK; + const guint8 *data = NULL; + guint available = 0; - /* Found a start code, search for the next one */ available = gst_adapter_available (parse->adapter); data = gst_adapter_peek (parse->adapter, available); - for (i = 4; i < available - 4; i++) { - /* We generate packets based on VOP start code */ - if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 && - data[i + 3] == 0xB6) { - GstBuffer *out_buf = gst_adapter_take_buffer (parse->adapter, i); - - GST_LOG_OBJECT (parse, "found next start code at %u", i); - if (out_buf) { - gst_buffer_set_caps (out_buf, GST_PAD_CAPS (parse->srcpad)); - gst_pad_push (parse->srcpad, out_buf); + + while (parse->offset < available - 4) { + /* We generate packets based on VOP end code (next start code) */ + if (data[parse->offset] == 0 && data[parse->offset + 1] == 0 && + data[parse->offset + 2] == 1) { + switch (parse->state) { + case PARSE_START_FOUND: + if (data[parse->offset + 3] == 0xB6) { + GST_LOG_OBJECT (parse, "found VOP start marker at %u", + parse->offset); + parse->state = PARSE_VOP_FOUND; + } + /* Jump over it */ + parse->offset += 4; + break; + case PARSE_VOP_FOUND: + { /* We were in a VOP already, any start code marks the end of it */ + GstBuffer *out_buf = gst_adapter_take_buffer (parse->adapter, + parse->offset); + + GST_LOG_OBJECT (parse, "found VOP end marker at %u", parse->offset); + if (out_buf) { + gst_buffer_set_caps (out_buf, GST_PAD_CAPS (parse->srcpad)); + gst_pad_push (parse->srcpad, out_buf); + } + /* Restart now that we flushed data */ + parse->offset = 0; + parse->state = PARSE_START_FOUND; + available = gst_adapter_available (parse->adapter); + data = gst_adapter_peek (parse->adapter, available); + break; + } + default: + GST_WARNING_OBJECT (parse, "unexpected parse state (%d)", + parse->state); + ret = GST_FLOW_UNEXPECTED; + goto beach; } - parse->found_start = FALSE; + } else { /* Continue searching */ + parse->offset++; } } @@ -116,8 +146,27 @@ gst_mpeg4vparse_chain (GstPad * pad, GstBuffer * buffer) gst_adapter_push (parse->adapter, buffer); + /* We need to get aligned on a start code */ + if (G_UNLIKELY (parse->state == PARSE_NEED_START)) { + gst_mpeg4vparse_align (parse); + /* No start code found in that buffer */ + if (G_UNLIKELY (parse->state == PARSE_NEED_START)) { + GST_DEBUG_OBJECT (parse, "start code not found, need more data"); + goto beach; + } + } + + /* We need at least 8 bytes to find the next start code which marks the end + of the one we just found */ + if (G_UNLIKELY (gst_adapter_available (parse->adapter) < 8)) { + GST_DEBUG_OBJECT (parse, "start code found, need more data to find next"); + goto beach; + } + + /* Drain the accumulated blocks frame per frame */ ret = gst_mpeg4vparse_drain (parse); +beach: gst_object_unref (parse); return ret; @@ -176,7 +225,8 @@ gst_mpeg4vparse_cleanup (GstMpeg4VParse * parse) gst_adapter_clear (parse->adapter); } - parse->found_start = FALSE; + parse->state = PARSE_NEED_START; + parse->offset = 0; } static GstStateChangeReturn -- cgit v1.2.1