diff options
author | Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> | 2011-01-06 11:41:44 +0100 |
---|---|---|
committer | Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> | 2011-01-28 12:16:57 +0100 |
commit | 829507b650fa907af2dbd651d29a63f68763700f (patch) | |
tree | 64297285d60250390fa5fdb3bf2f29936256798d | |
parent | 18b69e9320b8cad133e0b4696c32bcd8ffacc6c6 (diff) |
baseparse: allow increasing min_size for current frame parsing only
Also check that subclass actually either directs to skip bytes or
increases expected frame size to avoid going nowhere in bogus
indefinite looping.
-rw-r--r-- | gst/audioparsers/gstbaseparse.c | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/gst/audioparsers/gstbaseparse.c b/gst/audioparsers/gstbaseparse.c index 63ac08d45..b8b443521 100644 --- a/gst/audioparsers/gstbaseparse.c +++ b/gst/audioparsers/gstbaseparse.c @@ -82,7 +82,8 @@ * @framesize according to the detected frame size. If buffer didn't * contain a valid frame, this call must return FALSE and optionally * set the @skipsize value to inform base class that how many bytes - * it needs to skip in order to find a valid frame. The passed buffer + * it needs to skip in order to find a valid frame. @framesize can always + * indicate a new minimum for current frame parsing. The passed buffer * is read-only. Note that @check_valid_frame might receive any small * amount of input data when leftover data is being drained (e.g. at EOS). * </para></listitem> @@ -1874,7 +1875,7 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) guint fsize = 0; gint skip = -1; const guint8 *data; - guint min_size, av; + guint old_min_size = 0, min_size, av; GstClockTime timestamp; parse = GST_BASE_PARSE (GST_OBJECT_PARENT (pad)); @@ -1905,11 +1906,17 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) while (!parse->priv->flushing) { tmpbuf = gst_buffer_new (); + old_min_size = 0; /* Synchronization loop */ for (;;) { - min_size = parse->priv->min_frame_size; + min_size = MAX (parse->priv->min_frame_size, fsize); av = gst_adapter_available (parse->adapter); + /* loop safety check */ + if (G_UNLIKELY (old_min_size >= min_size)) + goto invalid_min; + old_min_size = min_size; + if (G_UNLIKELY (parse->priv->drain)) { min_size = av; GST_DEBUG_OBJECT (parse, "draining, data left: %d", min_size); @@ -1975,10 +1982,11 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) if (!parse->priv->discont) parse->priv->sync_offset = parse->priv->offset; parse->priv->discont = TRUE; + /* something changed least; nullify loop check */ + old_min_size = 0; } - /* There is a possibility that subclass set the skip value to zero. - This means that it has probably found a frame but wants to ask - more data (by increasing the min_size) to be sure of this. */ + /* skip == 0 should imply subclass set min_size to need more data; + * we check this shortly */ if ((ret = gst_base_parse_check_sync (parse)) != GST_FLOW_OK) { gst_buffer_unref (tmpbuf); goto done; @@ -2033,6 +2041,15 @@ gst_base_parse_chain (GstPad * pad, GstBuffer * buffer) done: GST_LOG_OBJECT (parse, "chain leaving"); return ret; + + /* ERRORS */ +invalid_min: + { + GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL), + ("min_size evolution %d -> %d; breaking to avoid looping", + old_min_size, min_size)); + return GST_FLOW_ERROR; + } } /* pull @size bytes at current offset, @@ -2180,14 +2197,18 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, { GstBuffer *buffer, *outbuf; GstFlowReturn ret = GST_FLOW_OK; - guint fsize = 0, min_size; + guint fsize = 0, min_size, old_min_size = 0; gint skip = 0; g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); while (TRUE) { - min_size = parse->priv->min_frame_size; + min_size = MAX (parse->priv->min_frame_size, fsize); + /* loop safety check */ + if (G_UNLIKELY (old_min_size >= min_size)) + goto invalid_min; + old_min_size = min_size; ret = gst_base_parse_pull_range (parse, min_size, &buffer); if (ret != GST_FLOW_OK) @@ -2227,8 +2248,11 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, if (!parse->priv->discont) parse->priv->sync_offset = parse->priv->offset; parse->priv->discont = TRUE; + /* something changed least; nullify loop check */ + old_min_size = 0; } - /* skip == 0 should imply subclass set min_size to need more data ... */ + /* skip == 0 should imply subclass set min_size to need more data; + * we check this shortly */ GST_DEBUG_OBJECT (parse, "finding sync..."); gst_buffer_unref (buffer); if ((ret = gst_base_parse_check_sync (parse)) != GST_FLOW_OK) { @@ -2264,6 +2288,15 @@ gst_base_parse_scan_frame (GstBaseParse * parse, GstBaseParseClass * klass, done: return ret; + + /* ERRORS */ +invalid_min: + { + GST_ELEMENT_ERROR (parse, STREAM, FAILED, (NULL), + ("min_size evolution %d -> %d; breaking to avoid looping", + old_min_size, min_size)); + return GST_FLOW_ERROR; + } } /** |