diff options
Diffstat (limited to 'gst/mpeg4videoparse')
-rw-r--r-- | gst/mpeg4videoparse/mpeg4videoparse.c | 106 | ||||
-rw-r--r-- | gst/mpeg4videoparse/mpeg4videoparse.h | 9 |
2 files changed, 86 insertions, 29 deletions
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 diff --git a/gst/mpeg4videoparse/mpeg4videoparse.h b/gst/mpeg4videoparse/mpeg4videoparse.h index 0fb434c3..94438ad2 100644 --- a/gst/mpeg4videoparse/mpeg4videoparse.h +++ b/gst/mpeg4videoparse/mpeg4videoparse.h @@ -40,6 +40,12 @@ G_BEGIN_DECLS typedef struct _GstMpeg4VParse GstMpeg4VParse; typedef struct _GstMpeg4VParseClass GstMpeg4VParseClass; +typedef enum { + PARSE_NEED_START, + PARSE_START_FOUND, + PARSE_VOP_FOUND +} GstMpeg4VParseState; + struct _GstMpeg4VParse { GstElement element; @@ -47,8 +53,9 @@ struct _GstMpeg4VParse { GstPad * srcpad; GstAdapter * adapter; + guint offset; - gboolean found_start; + GstMpeg4VParseState state; }; struct _GstMpeg4VParseClass { |