mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
matroskademux: not so fatal error handling
If some bits out of place in block(group) parsing, forego and move to next. Also skip large blocks in pull mode, but need to give up in push mode. Fixes #626463. Improves #620790.
This commit is contained in:
parent
680eb51b68
commit
4d9c1e99f2
1 changed files with 97 additions and 72 deletions
|
@ -4654,8 +4654,9 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
|
|
||||||
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||||
if (!is_simpleblock) {
|
if (!is_simpleblock) {
|
||||||
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK) {
|
||||||
break;
|
goto data_error;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
id = GST_MATROSKA_ID_SIMPLEBLOCK;
|
id = GST_MATROSKA_ID_SIMPLEBLOCK;
|
||||||
}
|
}
|
||||||
|
@ -4681,13 +4682,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
size = GST_BUFFER_SIZE (buf);
|
size = GST_BUFFER_SIZE (buf);
|
||||||
|
|
||||||
/* first byte(s): blocknum */
|
/* first byte(s): blocknum */
|
||||||
if ((n = gst_matroska_ebmlnum_uint (data, size, &num)) < 0) {
|
if ((n = gst_matroska_ebmlnum_uint (data, size, &num)) < 0)
|
||||||
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("Data error"));
|
goto data_error;
|
||||||
gst_buffer_unref (buf);
|
|
||||||
buf = NULL;
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data += n;
|
data += n;
|
||||||
size -= n;
|
size -= n;
|
||||||
|
|
||||||
|
@ -4695,15 +4691,16 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
stream_num = gst_matroska_demux_stream_from_num (demux, num);
|
stream_num = gst_matroska_demux_stream_from_num (demux, num);
|
||||||
if (G_UNLIKELY (size < 3)) {
|
if (G_UNLIKELY (size < 3)) {
|
||||||
GST_WARNING_OBJECT (demux, "Invalid size %u", size);
|
GST_WARNING_OBJECT (demux, "Invalid size %u", size);
|
||||||
ret = GST_FLOW_ERROR;
|
/* non-fatal, try next block(group) */
|
||||||
break;
|
ret = GST_FLOW_OK;
|
||||||
|
goto done;
|
||||||
} else if (G_UNLIKELY (stream_num < 0 ||
|
} else if (G_UNLIKELY (stream_num < 0 ||
|
||||||
stream_num >= demux->num_streams)) {
|
stream_num >= demux->num_streams)) {
|
||||||
/* let's not give up on a stray invalid track number */
|
/* let's not give up on a stray invalid track number */
|
||||||
GST_WARNING_OBJECT (demux,
|
GST_WARNING_OBJECT (demux,
|
||||||
"Invalid stream %d for track number %" G_GUINT64_FORMAT
|
"Invalid stream %d for track number %" G_GUINT64_FORMAT
|
||||||
"; ignoring block", stream_num, num);
|
"; ignoring block", stream_num, num);
|
||||||
break;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = g_ptr_array_index (demux->src, stream_num);
|
stream = g_ptr_array_index (demux->src, stream_num);
|
||||||
|
@ -4729,12 +4726,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
case 0x1: /* xiph lacing */
|
case 0x1: /* xiph lacing */
|
||||||
case 0x2: /* fixed-size lacing */
|
case 0x2: /* fixed-size lacing */
|
||||||
case 0x3: /* EBML lacing */
|
case 0x3: /* EBML lacing */
|
||||||
if (size == 0) {
|
if (size == 0)
|
||||||
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
|
goto invalid_lacing;
|
||||||
("Invalid lacing size"));
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
laces = GST_READ_UINT8 (data) + 1;
|
laces = GST_READ_UINT8 (data) + 1;
|
||||||
data += 1;
|
data += 1;
|
||||||
size -= 1;
|
size -= 1;
|
||||||
|
@ -4746,12 +4739,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
|
|
||||||
for (n = 0; ret == GST_FLOW_OK && n < laces - 1; n++) {
|
for (n = 0; ret == GST_FLOW_OK && n < laces - 1; n++) {
|
||||||
while (1) {
|
while (1) {
|
||||||
if (size == 0) {
|
if (size == 0)
|
||||||
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
|
goto invalid_lacing;
|
||||||
("Invalid lacing size"));
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
temp = GST_READ_UINT8 (data);
|
temp = GST_READ_UINT8 (data);
|
||||||
lace_size[n] += temp;
|
lace_size[n] += temp;
|
||||||
data += 1;
|
data += 1;
|
||||||
|
@ -4773,12 +4762,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
case 0x3: /* EBML lacing */ {
|
case 0x3: /* EBML lacing */ {
|
||||||
guint total;
|
guint total;
|
||||||
|
|
||||||
if ((n = gst_matroska_ebmlnum_uint (data, size, &num)) < 0) {
|
if ((n = gst_matroska_ebmlnum_uint (data, size, &num)) < 0)
|
||||||
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
|
goto data_error;
|
||||||
("Data error"));
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data += n;
|
data += n;
|
||||||
size -= n;
|
size -= n;
|
||||||
total = lace_size[0] = num;
|
total = lace_size[0] = num;
|
||||||
|
@ -4786,12 +4771,8 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
gint64 snum;
|
gint64 snum;
|
||||||
gint r;
|
gint r;
|
||||||
|
|
||||||
if ((r = gst_matroska_ebmlnum_sint (data, size, &snum)) < 0) {
|
if ((r = gst_matroska_ebmlnum_sint (data, size, &snum)) < 0)
|
||||||
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
|
goto data_error;
|
||||||
("Data error"));
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data += r;
|
data += r;
|
||||||
size -= r;
|
size -= r;
|
||||||
lace_size[n] = lace_size[n - 1] + snum;
|
lace_size[n] = lace_size[n - 1] + snum;
|
||||||
|
@ -4900,6 +4881,10 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* reading a number or so could have failed */
|
||||||
|
if (ret != GST_FLOW_OK)
|
||||||
|
goto data_error;
|
||||||
|
|
||||||
if (ret == GST_FLOW_OK && readblock) {
|
if (ret == GST_FLOW_OK && readblock) {
|
||||||
guint64 duration = 0;
|
guint64 duration = 0;
|
||||||
gint64 lace_time = 0;
|
gint64 lace_time = 0;
|
||||||
|
@ -5201,6 +5186,20 @@ eos:
|
||||||
ret = gst_matroska_demux_combine_flows (demux, stream, ret);
|
ret = gst_matroska_demux_combine_flows (demux, stream, ret);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
invalid_lacing:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_WARNING (demux, STREAM, DEMUX, (NULL), ("Invalid lacing size"));
|
||||||
|
/* non-fatal, try next block(group) */
|
||||||
|
ret = GST_FLOW_OK;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
data_error:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_WARNING (demux, STREAM, DEMUX, (NULL), ("Data error"));
|
||||||
|
/* non-fatal, try next block(group) */
|
||||||
|
ret = GST_FLOW_OK;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return FALSE if block(group) should be skipped (due to a seek) */
|
/* return FALSE if block(group) should be skipped (due to a seek) */
|
||||||
|
@ -5399,16 +5398,26 @@ gst_matroska_demux_parse_contents (GstMatroskaDemux * demux, GstEbmlRead * ebml)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GST_FLOW_OVERFLOW GST_FLOW_CUSTOM_ERROR
|
||||||
|
|
||||||
static inline GstFlowReturn
|
static inline GstFlowReturn
|
||||||
gst_matroska_demux_check_read_size (GstMatroskaDemux * demux, guint64 bytes)
|
gst_matroska_demux_check_read_size (GstMatroskaDemux * demux, guint64 bytes)
|
||||||
{
|
{
|
||||||
if (G_UNLIKELY (bytes > 10 * 1024 * 1024)) {
|
if (G_UNLIKELY (bytes > 10 * 1024 * 1024)) {
|
||||||
/* only a few blocks are expected/allowed to be large,
|
/* only a few blocks are expected/allowed to be large,
|
||||||
* and will be recursed into, whereas others will be read and must fit */
|
* and will be recursed into, whereas others will be read and must fit */
|
||||||
|
if (demux->streaming) {
|
||||||
|
/* fatal in streaming case, as we can't step over easily */
|
||||||
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
|
GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
|
||||||
("reading large block of size %" G_GUINT64_FORMAT " not supported; "
|
("reading large block of size %" G_GUINT64_FORMAT " not supported; "
|
||||||
"file might be corrupt.", bytes));
|
"file might be corrupt.", bytes));
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
|
} else {
|
||||||
|
/* indicate higher level to quietly give up */
|
||||||
|
GST_DEBUG_OBJECT (demux,
|
||||||
|
"too large block of size %" G_GUINT64_FORMAT, bytes);
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
@ -5431,37 +5440,6 @@ gst_matroska_demux_check_parse_error (GstMatroskaDemux * demux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initializes @ebml with @bytes from input stream at current offset.
|
|
||||||
* Returns UNEXPECTED if insufficient available,
|
|
||||||
* ERROR if too much was attempted to read. */
|
|
||||||
static inline GstFlowReturn
|
|
||||||
gst_matroska_demux_take (GstMatroskaDemux * demux, guint64 bytes,
|
|
||||||
GstEbmlRead * ebml)
|
|
||||||
{
|
|
||||||
GstBuffer *buffer = NULL;
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (demux, "taking %" G_GUINT64_FORMAT " bytes for parsing",
|
|
||||||
bytes);
|
|
||||||
ret = gst_matroska_demux_check_read_size (demux, bytes);
|
|
||||||
if (ret != GST_FLOW_OK)
|
|
||||||
goto exit;
|
|
||||||
if (demux->streaming) {
|
|
||||||
if (gst_adapter_available (demux->adapter) >= bytes)
|
|
||||||
buffer = gst_adapter_take_buffer (demux->adapter, bytes);
|
|
||||||
else
|
|
||||||
ret = GST_FLOW_UNEXPECTED;
|
|
||||||
} else
|
|
||||||
ret = gst_matroska_demux_peek_bytes (demux, demux->offset, bytes, &buffer,
|
|
||||||
NULL);
|
|
||||||
if (G_LIKELY (buffer)) {
|
|
||||||
gst_ebml_read_init (ebml, GST_ELEMENT_CAST (demux), buffer, demux->offset);
|
|
||||||
demux->offset += bytes;
|
|
||||||
}
|
|
||||||
exit:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline GstFlowReturn
|
static inline GstFlowReturn
|
||||||
gst_matroska_demux_flush (GstMatroskaDemux * demux, guint flush)
|
gst_matroska_demux_flush (GstMatroskaDemux * demux, guint flush)
|
||||||
{
|
{
|
||||||
|
@ -5482,6 +5460,46 @@ gst_matroska_demux_flush (GstMatroskaDemux * demux, guint flush)
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* initializes @ebml with @bytes from input stream at current offset.
|
||||||
|
* Returns UNEXPECTED if insufficient available,
|
||||||
|
* ERROR if too much was attempted to read. */
|
||||||
|
static inline GstFlowReturn
|
||||||
|
gst_matroska_demux_take (GstMatroskaDemux * demux, guint64 bytes,
|
||||||
|
GstEbmlRead * ebml)
|
||||||
|
{
|
||||||
|
GstBuffer *buffer = NULL;
|
||||||
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (demux, "taking %" G_GUINT64_FORMAT " bytes for parsing",
|
||||||
|
bytes);
|
||||||
|
ret = gst_matroska_demux_check_read_size (demux, bytes);
|
||||||
|
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
|
||||||
|
if (!demux->streaming) {
|
||||||
|
/* in pull mode, we can skip */
|
||||||
|
if ((ret = gst_matroska_demux_flush (demux, bytes)) == GST_FLOW_OK)
|
||||||
|
ret = GST_FLOW_OVERFLOW;
|
||||||
|
} else {
|
||||||
|
/* otherwise fatal */
|
||||||
|
ret = GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (demux->streaming) {
|
||||||
|
if (gst_adapter_available (demux->adapter) >= bytes)
|
||||||
|
buffer = gst_adapter_take_buffer (demux->adapter, bytes);
|
||||||
|
else
|
||||||
|
ret = GST_FLOW_UNEXPECTED;
|
||||||
|
} else
|
||||||
|
ret = gst_matroska_demux_peek_bytes (demux, demux->offset, bytes, &buffer,
|
||||||
|
NULL);
|
||||||
|
if (G_LIKELY (buffer)) {
|
||||||
|
gst_ebml_read_init (ebml, GST_ELEMENT_CAST (demux), buffer, demux->offset);
|
||||||
|
demux->offset += bytes;
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_matroska_demux_check_seekability (GstMatroskaDemux * demux)
|
gst_matroska_demux_check_seekability (GstMatroskaDemux * demux)
|
||||||
{
|
{
|
||||||
|
@ -5567,8 +5585,12 @@ gst_matroska_demux_find_tracks (GstMatroskaDemux * demux)
|
||||||
|
|
||||||
#define GST_READ_CHECK(stmt) \
|
#define GST_READ_CHECK(stmt) \
|
||||||
G_STMT_START { \
|
G_STMT_START { \
|
||||||
if (G_UNLIKELY ((ret = (stmt)) != GST_FLOW_OK)) \
|
if (G_UNLIKELY ((ret = (stmt)) != GST_FLOW_OK)) { \
|
||||||
|
if (ret == GST_FLOW_OVERFLOW) { \
|
||||||
|
ret = GST_FLOW_OK; \
|
||||||
|
} \
|
||||||
goto read_error; \
|
goto read_error; \
|
||||||
|
} \
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -5579,6 +5601,9 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
guint64 read;
|
guint64 read;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (demux, "Parsing Element id 0x%x, "
|
||||||
|
"size %" G_GUINT64_FORMAT ", prefix %d", id, length, needed);
|
||||||
|
|
||||||
/* if we plan to read and parse this element, we need prefix (id + length)
|
/* if we plan to read and parse this element, we need prefix (id + length)
|
||||||
* and the contents */
|
* and the contents */
|
||||||
/* mind about overflow wrap-around when dealing with undefined size */
|
/* mind about overflow wrap-around when dealing with undefined size */
|
||||||
|
|
Loading…
Reference in a new issue