pesparse: Refactory secondary PES extension handling

Some streams had wrong values for the stream_id_extension, make sure
we only remember the valid ones.

For streams with PES_extension_field_length == 0, assume there's nothing
else.

For streams that state they have a TREF extension but don't have enough
data to store it, just assume it was produced by a non-compliant muxer
and skip the remaining data.

Only store remaining data in stream_id_extension_data instead of storing
data we already parse.
This commit is contained in:
Edward Hervey 2013-08-14 13:41:37 +02:00
parent 131c263248
commit 21ebc7708d
2 changed files with 52 additions and 32 deletions

View file

@ -256,7 +256,12 @@ mpegts_parse_pes_header (const guint8 * data, gsize length, PESHeader * res)
/* PES extension */ /* PES extension */
flags = *data++; flags = *data++;
length -= 1; length -= 1;
GST_DEBUG ("PES_extension_flag 0x%02x", flags); GST_DEBUG ("PES_extension_flag: %s%s%s%s%s%s",
flags & 0x80 ? "PES_private_data " : "",
flags & 0x40 ? "pack_header_field " : "",
flags & 0x20 ? "program_packet_sequence_counter " : "",
flags & 0x10 ? "P-STD_buffer " : "",
flags & 0x01 ? "PES_extension_flag_2" : "", flags & 0xf1 ? "" : "<none>");
if (flags & 0x80) { if (flags & 0x80) {
/* PES_private data */ /* PES_private data */
@ -292,7 +297,6 @@ mpegts_parse_pes_header (const guint8 * data, gsize length, PESHeader * res)
goto need_more_data; goto need_more_data;
val8 = *data++; val8 = *data++;
/* GRMBL, this is most often wrong */
if (G_UNLIKELY ((val8 & 0x80) != 0x80)) if (G_UNLIKELY ((val8 & 0x80) != 0x80))
goto bad_sequence_marker1; goto bad_sequence_marker1;
res->program_packet_sequence_counter = val8 & 0x7f; res->program_packet_sequence_counter = val8 & 0x7f;
@ -300,7 +304,6 @@ mpegts_parse_pes_header (const guint8 * data, gsize length, PESHeader * res)
res->program_packet_sequence_counter); res->program_packet_sequence_counter);
val8 = *data++; val8 = *data++;
/* GRMBL, this is most often wrong */
if (G_UNLIKELY ((val8 & 0x80) != 0x80)) if (G_UNLIKELY ((val8 & 0x80) != 0x80))
goto bad_sequence_marker2; goto bad_sequence_marker2;
res->MPEG1_MPEG2_identifier = (val8 >> 6) & 0x1; res->MPEG1_MPEG2_identifier = (val8 >> 6) & 0x1;
@ -324,37 +327,52 @@ mpegts_parse_pes_header (const guint8 * data, gsize length, PESHeader * res)
length -= 2; length -= 2;
} }
if (flags & 0x01) { /* jump if we don't have a PES 2nd extension */
/* Extension flag 2 */ if (!flags & 0x01)
if (G_UNLIKELY (length < 1)) goto stuffing_byte;
goto need_more_data;
val8 = *data++; /* Extension flag 2 */
length -= 1; if (G_UNLIKELY (length < 1))
goto need_more_data;
if (!(val8 & 0x80)) val8 = *data++;
goto bad_extension_marker_2; length -= 1;
res->extension_field_length = val8 & 0x7f; if (!(val8 & 0x80))
if (G_UNLIKELY (length < res->extension_field_length)) goto bad_extension_marker_2;
goto need_more_data;
GST_LOG ("extension_field_length : %" G_GSIZE_FORMAT, res->extension_field_length = val8 & 0x7f;
res->extension_field_length);
if (res->extension_field_length) { /* Skip empty extensions */
flags = *data++; if (G_UNLIKELY (res->extension_field_length == 0))
/* Only valid if stream_id_extension_flag == 0x0 */ goto stuffing_byte;
if (!(flags & 0x80)) {
res->stream_id_extension = flags & 0x7f; if (G_UNLIKELY (length < res->extension_field_length))
GST_LOG ("stream_id_extension : 0x%02x", res->stream_id_extension); goto need_more_data;
res->stream_id_extension_data = data;
GST_MEMDUMP ("stream_id_extension_data", flags = *data++;
res->stream_id_extension_data, res->extension_field_length); res->extension_field_length -= 1;
} else {
GST_LOG ("tref_extension : %d", flags & 0x01); if (!(flags & 0x80)) {
} /* Only valid if stream_id_extension_flag == 0x0 */
} res->stream_id_extension = flags;
GST_LOG ("stream_id_extension : 0x%02x", res->stream_id_extension);
} else if (!(flags & 0x01)) {
/* Skip broken streams (that use stream_id_extension with highest bit set
* for example ...) */
if (G_UNLIKELY (res->extension_field_length < 5))
goto stuffing_byte;
GST_LOG ("TREF field present");
data += 5;
res->extension_field_length -= 5;
}
/* Extension field data */
if (res->extension_field_length) {
res->stream_id_extension_data = data;
GST_MEMDUMP ("stream_id_extension_data",
res->stream_id_extension_data, res->extension_field_length);
} }
stuffing_byte: stuffing_byte:

View file

@ -185,9 +185,11 @@ typedef struct {
guint32 P_STD_buffer_size; /* P-STD buffer size in bytes (0 if invalid guint32 P_STD_buffer_size; /* P-STD buffer size in bytes (0 if invalid
* or not present */ * or not present */
gsize extension_field_length; guint8 stream_id_extension; /* Public range (0x00 - 0x3f) only valid if stream_id == ID_EXTENDED_STREAM_ID
guint8 stream_id_extension; /* Only valid if stream_id == ID_EXTENDED_STREAM_ID */ * Private range (0x40 - 0xff) can be present in any stream type */
const guint8* stream_id_extension_data;
gsize extension_field_length; /* Length of remaining extension field data */
const guint8* stream_id_extension_data; /* Valid if extension_field_length != 0 */
} PESHeader; } PESHeader;
G_GNUC_INTERNAL PESParsingResult mpegts_parse_pes_header (const guint8* data, G_GNUC_INTERNAL PESParsingResult mpegts_parse_pes_header (const guint8* data,