--- a/gst/mpegdemux/gstmpegdemux.c +++ b/gst/mpegdemux/gstmpegdemux.c @@ -48,6 +48,8 @@ #include <string.h> +#include <gst/base/gstbytereader.h> + #include "gstmpegdefs.h" #include "gstmpegdemux.h" @@ -1880,94 +1882,118 @@ static GstFlowReturn gst_flups_demux_parse_psm (GstFluPSDemux * demux) { - guint16 length = 0, info_length = 0, es_map_length = 0; + guint16 psm_length = 0, info_length = 0, es_map_length = 0; guint8 psm_version = 0; - const guint8 *data, *es_map_base; + GstByteReader br; gboolean applicable; - /* start code + length */ - if (!(data = gst_adapter_peek (demux->adapter, 6))) + /* Need at least 6 bytes for start code + length */ + if (gst_adapter_available (demux->adapter) < 6) goto need_more_data; - /* skip start code */ - data += 4; + { + const guint8 *data; - length = GST_READ_UINT16_BE (data); - GST_DEBUG_OBJECT (demux, "length %u", length); + /* start code + length */ + data = gst_adapter_peek (demux->adapter, 6); - if (G_UNLIKELY (length > 0x3FA)) - goto psm_len_error; + /* skip start code */ + data += 4; - length += 6; + psm_length = GST_READ_UINT16_BE (data); + GST_DEBUG_OBJECT (demux, "length %u", psm_length); - if (!(data = gst_adapter_peek (demux->adapter, length))) - goto need_more_data; + if (G_UNLIKELY (psm_length > 0x3FA)) + goto psm_len_error; - /* skip start code and length */ - data += 6; + psm_length += 6; /* Add start code + size to length */ + + if (gst_adapter_available (demux->adapter) < psm_length) + goto need_more_data; + + data = gst_adapter_peek (demux->adapter, psm_length); + + gst_byte_reader_init (&br, data, psm_length); + } + + if (!gst_byte_reader_skip (&br, 6)) + goto fail_invalid; /* Read PSM applicable bit together with version */ - psm_version = GST_READ_UINT8 (data); + if (!gst_byte_reader_get_uint8 (&br, &psm_version)) + goto fail_invalid; applicable = (psm_version & 0x80) >> 7; psm_version &= 0x1F; GST_DEBUG_OBJECT (demux, "PSM version %u (applicable now %u)", psm_version, applicable); - /* Jump over version and marker bit */ - data += 2; + /* Jump over the next byte (marker bit) */ + if (!gst_byte_reader_skip (&br, 1)) + goto fail_invalid; /* Read PS info length */ - info_length = GST_READ_UINT16_BE (data); - /* Cap it to PSM length - needed bytes for ES map length and CRC */ - info_length = MIN (length - 16, info_length); + if (!gst_byte_reader_get_uint16_be (&br, &info_length)) + goto fail_invalid; GST_DEBUG_OBJECT (demux, "PS info length %u bytes", info_length); - /* Jump over that section */ - data += (2 + info_length); + /* Skip the PS info, we don't use it */ + if (!gst_byte_reader_skip (&br, info_length)) + goto fail_invalid; /* Read ES map length */ - es_map_length = GST_READ_UINT16_BE (data); - /* Cap it to PSM remaining length - CRC */ - es_map_length = MIN (length - (16 + info_length), es_map_length); + if (!gst_byte_reader_get_uint16_be (&br, &es_map_length)) + goto fail_invalid; GST_DEBUG_OBJECT (demux, "ES map length %u bytes", es_map_length); - /* Jump over the size */ - data += 2; - /* Now read the ES map */ - es_map_base = data; - while (es_map_base + 4 <= data + es_map_length) { - guint8 stream_type = 0, stream_id = 0; - guint16 stream_info_length = 0; - - stream_type = GST_READ_UINT8 (es_map_base); - es_map_base++; - stream_id = GST_READ_UINT8 (es_map_base); - es_map_base++; - stream_info_length = GST_READ_UINT16_BE (es_map_base); - es_map_base += 2; - /* Cap stream_info_length */ - stream_info_length = MIN (data + es_map_length - es_map_base, - stream_info_length); - - GST_DEBUG_OBJECT (demux, "Stream type %02X with id %02X and %u bytes info", - stream_type, stream_id, stream_info_length); - if (G_LIKELY (stream_id != 0xbd)) - demux->psm[stream_id] = stream_type; - else { - /* Ignore stream type for private_stream_1 and discover it looking at - * the stream data. - * Fixes demuxing some clips with lpcm that was wrongly declared as - * mpeg audio */ - GST_DEBUG_OBJECT (demux, "stream type for private_stream_1 ignored"); - } - es_map_base += stream_info_length; - } + { + GstByteReader es_map_br; + const guint8 *data; - gst_adapter_flush (demux->adapter, length); - ADAPTER_OFFSET_FLUSH (length); + if (!gst_byte_reader_get_data (&br, es_map_length, &data)) + goto fail_invalid; + + gst_byte_reader_init (&es_map_br, data, es_map_length); + + while (gst_byte_reader_get_remaining (&es_map_br) >= 4) { + guint8 stream_type = 0, stream_id = 0; + guint16 stream_info_length = 0; + + if (!gst_byte_reader_get_uint8 (&es_map_br, &stream_type) || + !gst_byte_reader_get_uint8 (&es_map_br, &stream_id) || + !gst_byte_reader_get_uint16_be (&es_map_br, &stream_info_length)) + break; + + GST_DEBUG_OBJECT (demux, + "Stream type %02X with id %02X and %u bytes info", stream_type, + stream_id, stream_info_length); + + if (G_LIKELY (stream_id != 0xbd)) + demux->psm[stream_id] = stream_type; + else { + /* Ignore stream type for private_stream_1 and discover it looking at + * the stream data. + * Fixes demuxing some clips with lpcm that was wrongly declared as + * mpeg audio */ + GST_DEBUG_OBJECT (demux, "stream type for private_stream_1 ignored"); + } + + /* FIXME: We could use the descriptors instead of skipping them */ + if (!gst_byte_reader_skip (&es_map_br, stream_info_length)) + break; + } + } + /* We ignore the 4-byte CRC at the end */ + + gst_adapter_flush (demux->adapter, psm_length); + ADAPTER_OFFSET_FLUSH (psm_length); return GST_FLOW_OK; +fail_invalid: + GST_DEBUG_OBJECT (demux, "Failed to parse PSM. Skipping"); + gst_adapter_flush (demux->adapter, psm_length); + ADAPTER_OFFSET_FLUSH (psm_length); + return GST_FLOW_LOST_SYNC; psm_len_error: { GST_DEBUG_OBJECT (demux, "error in PSM length");