gst/typefind/gsttypefindfunctions.c: Consolidate and re-work our mpeg system stream detection to probe more packets a...

Original commit message from CVS:
* gst/typefind/gsttypefindfunctions.c: (mpeg_sys_is_valid_pack),
(mpeg_sys_is_valid_pes), (mpeg_sys_is_valid_sys),
(mpeg_sys_type_find), (mpeg_ts_type_find), (mpeg4_video_type_find),
(mpeg_video_type_find), (mpeg_video_stream_type_find),
(plugin_init):
Consolidate and re-work our mpeg system stream detection to probe
more packets and produce a higher confidence result. Fixes a
regression caused by lowering the typefind probability last year
- related to bug #397810. Remove the redundant MPEG-1 specific
typefind function, as the new one detects both MPEG-1 & MPEG-2
happily.
Also cleanup the MPEG elementary and MPEG-TS detection functions a
little.
Tested against my media test directory, with some improvements and
no regressions.
This commit is contained in:
Jan Schmidt 2007-05-11 17:33:43 +00:00
parent 56f01bc0cb
commit 1e2c327792
3 changed files with 273 additions and 208 deletions

View file

@ -1,3 +1,24 @@
2007-05-11 Jan Schmidt <thaytan@mad.scientist.com>
* gst/typefind/gsttypefindfunctions.c: (mpeg_sys_is_valid_pack),
(mpeg_sys_is_valid_pes), (mpeg_sys_is_valid_sys),
(mpeg_sys_type_find), (mpeg_ts_type_find), (mpeg4_video_type_find),
(mpeg_video_type_find), (mpeg_video_stream_type_find),
(plugin_init):
Consolidate and re-work our mpeg system stream detection to probe
more packets and produce a higher confidence result. Fixes a
regression caused by lowering the typefind probability last year
- related to bug #397810. Remove the redundant MPEG-1 specific
typefind function, as the new one detects both MPEG-1 & MPEG-2
happily.
Also cleanup the MPEG elementary and MPEG-TS detection functions a
little.
Tested against my media test directory, with some improvements and
no regressions.
2007-05-10 Wim Taymans <wim@fluendo.com> 2007-05-10 Wim Taymans <wim@fluendo.com>
* gst/playback/gstplaybasebin.c: (fill_buffer), (check_queue), * gst/playback/gstplaybasebin.c: (fill_buffer), (check_queue),

2
common

@ -1 +1 @@
Subproject commit 1b4fb5836a9e290fe13895643d41e0166de8a94c Subproject commit b5971d76ccd216c27e095c02c3a369a9d05cb36d

View file

@ -1094,219 +1094,259 @@ static GstStaticCaps mpeg_sys_caps = GST_STATIC_CAPS ("video/mpeg, "
(((guint8 *)(data))[1] == 0x00) && \ (((guint8 *)(data))[1] == 0x00) && \
(((guint8 *)(data))[2] == 0x01)) (((guint8 *)(data))[2] == 0x01))
#define IS_MPEG_PACK_CODE(b) ((b) == 0xBA)
#define IS_MPEG_SYS_CODE(b) ((b) == 0xBB)
#define IS_MPEG_PACK_HEADER(data) (IS_MPEG_HEADER (data) && \ #define IS_MPEG_PACK_HEADER(data) (IS_MPEG_HEADER (data) && \
(((guint8 *)(data))[3] == 0xBA)) IS_MPEG_PACK_CODE (((guint8 *)(data))[3]))
#define IS_MPEG_SYSTEM_HEADER(data) (IS_MPEG_HEADER (data) && \
(((guint8 *)(data))[3] == 0xBB))
#define IS_MPEG_PACKET_HEADER(data) (IS_MPEG_HEADER (data) && \
((((guint8 *)(data))[3] & 0x80) == 0x80))
#define IS_MPEG_PES_CODE(b) (((b) & 0xF0) == 0xE0 || ((b) & 0xF0) == 0xC0 || \
(b) >= 0xBD)
#define IS_MPEG_PES_HEADER(data) (IS_MPEG_HEADER (data) && \ #define IS_MPEG_PES_HEADER(data) (IS_MPEG_HEADER (data) && \
((((guint8 *)(data))[3] == 0xE0) || \ IS_MPEG_PES_CODE (((guint8 *)(data))[3]))
(((guint8 *)(data))[3] == 0xC0) || \
(((guint8 *)(data))[3] == 0xBD)))
#define MPEG2_MAX_PROBE_LENGTH 4096 /* 4kB (random value) */ #define MPEG2_MAX_PROBE_LENGTH (32 * 1024) /* 32kB should be 16 packs of the
* most common 2kB pack size, but HD
* streams might be bigger. */
static void #define MPEG2_MIN_SYS_HEADERS 2
mpeg2_sys_type_find (GstTypeFind * tf, gpointer unused) #define MPEG2_MAX_SYS_HEADERS 5
static gboolean
mpeg_sys_is_valid_pack (GstTypeFind * tf, guint8 * data, guint len,
guint * pack_size)
{ {
guint8 *data, *data0; /* Check the pack header @ offset for validity, assuming that the 4 byte header
gint mpegversion, len; * itself has already been checked. */
guint8 stuff_len;
len = MPEG2_MAX_PROBE_LENGTH * 2; if (len < 12)
do { return FALSE;
len = len / 2;
data = gst_type_find_peek (tf, 0, 5 + len);
} while (data == NULL && len >= 32);
if (!data) /* Check marker bits */
return; if ((data[4] & 0xC4) == 0x44) {
/* MPEG-2 PACK */
if (len < 14)
return FALSE;
data0 = data; if ((data[6] & 0x04) != 0x04 ||
while (len > 0) { (data[8] & 0x04) != 0x04 ||
if (IS_MPEG_PACK_HEADER (data)) { (data[9] & 0x01) != 0x01 || (data[12] & 0x03) != 0x03)
if ((data[4] & 0xC0) == 0x40) { return FALSE;
/* type 2 */
mpegversion = 2; stuff_len = data[13] & 0x07;
goto suggest;
} else if ((data[4] & 0xF0) == 0x20) { /* Check the following header bytes, if we can */
mpegversion = 1; if ((14 + stuff_len + 4) <= len) {
goto suggest; if (!IS_MPEG_HEADER (data + 14 + stuff_len))
} return FALSE;
} else if (IS_MPEG_PES_HEADER (data)) {
/* PES stream */
mpegversion = 2;
goto suggest;
} }
++data; if (pack_size)
--len; *pack_size = 14 + stuff_len;
} return TRUE;
return; } else if ((data[4] & 0xF1) == 0x21) {
suggest: /* MPEG-1 PACK */
{ if ((data[6] & 0x01) != 0x01 ||
GstCaps *caps = gst_caps_copy (MPEG_SYS_CAPS); (data[8] & 0x01) != 0x01 ||
(data[9] & 0x80) != 0x80 || (data[11] & 0x01) != 0x01)
return FALSE;
gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion", /* Check the following header bytes, if we can */
G_TYPE_INT, mpegversion, NULL); if ((12 + 4) <= len) {
/* lower probability if the marker isn't right at the start */ if (!IS_MPEG_HEADER (data + 12))
if (data0 == data) return FALSE;
gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, caps); }
else if (pack_size)
gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE - 10, caps); *pack_size = 12;
gst_caps_unref (caps); return TRUE;
} }
};
/* ATTENTION: ugly return value: return FALSE;
* 0 - invalid data }
* 1 - not enough data
* anything else - size until next package static gboolean
*/ mpeg_sys_is_valid_pes (GstTypeFind * tf, guint8 * data, guint len,
static guint guint * pack_size)
mpeg1_parse_header (GstTypeFind * tf, guint64 offset)
{ {
guint8 *data = gst_type_find_peek (tf, offset, 4); guint pes_packet_len;
guint size;
if (!data) { /* Check the PES header at the given position, assuming the header code itself
GST_LOG ("couldn't get MPEG header bytes"); * was already checked */
return 1; if (len < 6)
return FALSE;
/* For MPEG Program streams, unbounded PES is not allowed, so we must have a
* valid length present */
pes_packet_len = GST_READ_UINT16_BE (data + 4);
if (pes_packet_len == 0)
return FALSE;
/* Check the following header, if we can */
if (6 + pes_packet_len + 4 <= len) {
if (!IS_MPEG_HEADER (data + 6 + pes_packet_len))
return FALSE;
} }
if (data[0] != 0 || data[1] != 0 || data[2] != 1) { if (pack_size)
GST_LOG ("no sync"); *pack_size = 6 + pes_packet_len;
return 0; return TRUE;
} }
offset += 4;
GST_LOG ("sync %02x", data[3]); static gboolean
mpeg_sys_is_valid_sys (GstTypeFind * tf, guint8 * data, guint len,
guint * pack_size)
{
guint sys_hdr_len;
switch (data[3]) { /* Check the System header at the given position, assuming the header code itself
case 0xBA: /* pack header */ * was already checked */
data = gst_type_find_peek (tf, offset, 8); if (len < 6)
if (!data) { return FALSE;
GST_LOG ("couldn't get MPEG pack header bytes"); sys_hdr_len = GST_READ_UINT16_BE (data + 4);
return 1; if (sys_hdr_len < 6)
} return FALSE;
size = 12;
/* check marker bits */
if ((data[0] & 0xF1) != 0x21 ||
(data[2] & 0x01) != 0x01 ||
(data[4] & 0x01) != 0x01 ||
(data[5] & 0x80) != 0x80 || (data[7] & 0x01) != 0x01) {
GST_LOG ("wrong marker bits");
return 0;
}
break;
case 0xB9: /* ISO end code */ /* Check the following header, if we can */
size = 4; if (6 + sys_hdr_len + 4 <= len) {
break; if (!IS_MPEG_HEADER (data + 6 + sys_hdr_len))
return FALSE;
case 0xBB: /* system header */
data = gst_type_find_peek (tf, offset, 2);
if (!data) {
GST_LOG ("couldn't get MPEG pack header bytes");
return 1;
}
size = GST_READ_UINT16_BE (data) + 6;
offset += 2;
data = gst_type_find_peek (tf, offset, size - 6);
if (!data) {
GST_LOG ("couldn't get MPEG pack header bytes");
return 1;
}
/* check marker bits */
if ((data[0] & 0x80) != 0x80 ||
(data[2] & 0x01) != 0x01 || (data[4] & 0x20) != 0x20) {
GST_LOG ("wrong marker bits");
return 0;
}
/* check stream marker bits */
for (offset = 6; offset < (size - 6); offset += 3) {
if (data[offset] <= 0xBB || (data[offset + 1] & 0xC0) != 0xC0) {
GST_LOG ("wrong marker bits");
return 0;
}
}
break;
default:
if (data[3] < 0xB9)
return 0;
data = gst_type_find_peek (tf, offset, 2);
if (!data) {
GST_LOG ("couldn't get MPEG pack header bytes");
return 1;
}
size = GST_READ_UINT16_BE (data) + 6;
/* FIXME: we could check PTS/DTS marker bits here... (bit overkill) */
break;
} }
return size; if (pack_size)
*pack_size = 6 + sys_hdr_len;
return TRUE;
} }
/* calculation of possibility to identify random data as mpeg systemstream: /* calculation of possibility to identify random data as mpeg systemstream:
* bits that must match in header detection: 32 (or more) * bits that must match in header detection: 32 (or more)
* chance that random data is identifed: 1/2^32 * chance that random data is identifed: 1/2^32
* chance that GST_MPEG_TYPEFIND_TRY_HEADERS headers are identified: * chance that MPEG2_MIN_PACK_HEADERS headers are identified:
* 1/2^(32*GST_MPEG_TYPEFIND_TRY_HEADERS) * 1/2^(32*MPEG2_MIN_PACK_HEADERS)
* chance that this happens in GST_MPEG_TYPEFIND_TRY_SYNC bytes: * chance that this happens in MPEG2_MAX_PROBE_LENGTH bytes:
* 1-(1+1/2^(32*GST_MPEG_TYPEFIND_TRY_HEADERS)^GST_MPEG_TYPEFIND_TRY_SYNC) * 1-(1+1/2^(32*MPEG2_MIN_PACK_HEADERS)^MPEG2_MAX_PROBE_LENGTH)
* for current values: * for current values:
* 1-(1+1/2^(32*4)^101024) * 1-(1+1/2^(32*4)^101024)
* = <some_number> * = <some_number>
* Since we also check marker bits and pes packet lengths, this probability is a
* very coarse upper bound.
*/ */
#define GST_MPEG_TYPEFIND_TRY_HEADERS 4
#define GST_MPEG_TYPEFIND_TRY_SYNC (100 * 1024) /* 100kB */
#define GST_MPEG_TYPEFIND_SYNC_SIZE 2048
static void static void
mpeg1_sys_type_find (GstTypeFind * tf, gpointer unused) mpeg_sys_type_find (GstTypeFind * tf, gpointer unused)
{ {
guint8 *data = NULL; guint8 *data, *data0, *first_sync, *end;
guint size = 0; gint mpegversion = 0;
guint64 skipped = 0; guint pack_headers = 0;
GstCaps *caps; guint pes_headers = 0;
guint pack_size;
guint since_last_sync = 0;
guint32 sync_word = 0xffffffff;
while (skipped < GST_MPEG_TYPEFIND_TRY_SYNC) { G_STMT_START {
if (size < 4) { gint len;
data = gst_type_find_peek (tf, skipped, GST_MPEG_TYPEFIND_SYNC_SIZE);
if (!data)
break;
size = GST_MPEG_TYPEFIND_SYNC_SIZE;
}
if (IS_MPEG_PACK_HEADER (data)) {
/* found packet start code */
guint found = 0;
guint packet_size = 0;
guint64 offset = skipped;
while (found < GST_MPEG_TYPEFIND_TRY_HEADERS) { len = MPEG2_MAX_PROBE_LENGTH;
packet_size = mpeg1_parse_header (tf, offset); do {
if (packet_size <= 1) len = len / 2;
break; data = gst_type_find_peek (tf, 0, 5 + len);
offset += packet_size; } while (data == NULL && len >= 32);
found++;
} if (!data)
g_assert (found <= GST_MPEG_TYPEFIND_TRY_HEADERS); return;
if (found == GST_MPEG_TYPEFIND_TRY_HEADERS || packet_size == 1) {
GST_LOG ("suggesting mpeg1 system steeam"); end = data + len;
caps = gst_caps_copy (MPEG_SYS_CAPS);
gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
G_TYPE_INT, 1, NULL);
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 1, caps);
gst_caps_unref (caps);
return;
}
}
data++;
skipped++;
size--;
} }
} G_STMT_END;
data0 = data;
first_sync = NULL;
while (data < end) {
sync_word <<= 8;
if (sync_word == 0x00000100) {
/* Found potential sync word */
if (first_sync == NULL)
first_sync = data - 3;
if (since_last_sync > 4) {
/* If more than 4 bytes since the last sync word, reset our counters,
* as we're only interested in counting contiguous packets */
pes_headers = pack_headers = 0;
}
pack_size = 0;
if (IS_MPEG_PACK_CODE (data[0])) {
if ((data[1] & 0xC0) == 0x40) {
/* MPEG-2 */
mpegversion = 2;
} else if ((data[1] & 0xF0) == 0x20) {
mpegversion = 1;
}
if (mpegversion != 0 &&
mpeg_sys_is_valid_pack (tf, data - 3, end - data + 3, &pack_size)) {
pack_headers++;
}
} else if (IS_MPEG_PES_CODE (data[0])) {
/* PES stream */
if (mpeg_sys_is_valid_pes (tf, data - 3, end - data + 3, &pack_size)) {
pes_headers++;
if (mpegversion == 0)
mpegversion = 2;
}
} else if (IS_MPEG_SYS_CODE (data[0])) {
if (mpeg_sys_is_valid_sys (tf, data - 3, end - data + 3, &pack_size)) {
pack_headers++;
}
}
/* If we found a packet with a known size, skip the bytes in it and loop
* around to check the next packet. */
if (pack_size != 0) {
data += pack_size - 3;
sync_word = 0xffffffff;
since_last_sync = 0;
continue;
}
}
sync_word |= data[0];
since_last_sync++;
data++;
/* If we have found MAX headers, and *some* were pes headers (pack headers
* are optional in an mpeg system stream) then return our high-probability
* result */
if (pes_headers > 0 && (pack_headers + pes_headers) > MPEG2_MAX_SYS_HEADERS)
goto suggest;
}
/* If we at least saw MIN headers, and *some* were pes headers (pack headers
* are optional in an mpeg system stream) then return a lower-probability
* result */
if (pes_headers > 0 && (pack_headers + pes_headers) > MPEG2_MIN_SYS_HEADERS)
goto suggest;
return;
suggest:
{
GstCaps *caps = gst_caps_copy (MPEG_SYS_CAPS);
guint prob;
prob = GST_TYPE_FIND_POSSIBLE + (10 * (pack_headers + pes_headers));
prob = MIN (prob, GST_TYPE_FIND_MAXIMUM);
/* lower probability if the first packet wasn't right at the start */
if (data0 != first_sync && prob >= 10)
prob -= 10;
GST_LOG ("Suggesting MPEG %d system stream, %d packs, %d pes, prob %u%%\n",
mpegversion, pack_headers, pes_headers, prob);
gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
G_TYPE_INT, mpegversion, NULL);
gst_type_find_suggest (tf, prob, caps);
gst_caps_unref (caps);
}
};
/** video/mpegts Transport Stream **/ /** video/mpegts Transport Stream **/
static GstStaticCaps mpegts_caps = GST_STATIC_CAPS ("video/mpegts, " static GstStaticCaps mpegts_caps = GST_STATIC_CAPS ("video/mpegts, "
@ -1315,13 +1355,14 @@ static GstStaticCaps mpegts_caps = GST_STATIC_CAPS ("video/mpegts, "
#define GST_MPEGTS_TYPEFIND_MIN_HEADERS 4 #define GST_MPEGTS_TYPEFIND_MIN_HEADERS 4
#define GST_MPEGTS_TYPEFIND_MAX_HEADERS 10 #define GST_MPEGTS_TYPEFIND_MAX_HEADERS 10
#define GST_MPEGTS_MAX_PACKET_SIZE 204 #define GST_MPEGTS_MAX_PACKET_SIZE 208
#define GST_MPEGTS_TYPEFIND_SYNC_SIZE \ #define GST_MPEGTS_TYPEFIND_SYNC_SIZE \
(GST_MPEGTS_TYPEFIND_MIN_HEADERS * GST_MPEGTS_MAX_PACKET_SIZE) (GST_MPEGTS_TYPEFIND_MIN_HEADERS * GST_MPEGTS_MAX_PACKET_SIZE)
#define GST_MPEGTS_TYPEFIND_MAX_SYNC \ #define GST_MPEGTS_TYPEFIND_MAX_SYNC \
(GST_MPEGTS_TYPEFIND_MAX_HEADERS * GST_MPEGTS_MAX_PACKET_SIZE) (GST_MPEGTS_TYPEFIND_MAX_HEADERS * GST_MPEGTS_MAX_PACKET_SIZE)
#define MPEGTS_HDR_SIZE 4 #define MPEGTS_HDR_SIZE 4
/* Check for sync byte, error_indicator == 0 and packet has payload */
#define IS_MPEGTS_HEADER(data) (((data)[0] == 0x47) && \ #define IS_MPEGTS_HEADER(data) (((data)[0] == 0x47) && \
(((data)[1] & 0x80) == 0x00) && \ (((data)[1] & 0x80) == 0x00) && \
(((data)[3] & 0x10) == 0x10)) (((data)[3] & 0x10) == 0x10))
@ -1389,8 +1430,7 @@ mpeg_ts_type_find (GstTypeFind * tf, gpointer unused)
/* found at least 4 headers. 10 headers = MAXIMUM probability. /* found at least 4 headers. 10 headers = MAXIMUM probability.
* Arbitrarily, I assigned 10% probability for each header we * Arbitrarily, I assigned 10% probability for each header we
* found, 40% -> 100% */ * found, 40% -> 100% */
probability = MIN (10 * found, GST_TYPE_FIND_MAXIMUM);
probability = 10 * MIN (found, 10);
gst_type_find_suggest (tf, probability, caps); gst_type_find_suggest (tf, probability, caps);
gst_caps_unref (caps); gst_caps_unref (caps);
@ -1424,7 +1464,7 @@ mpeg4_video_type_find (GstTypeFind * tf, gpointer unused)
while (TRUE) { while (TRUE) {
data = gst_type_find_peek (tf, offset, 4); data = gst_type_find_peek (tf, offset, 4);
if (data && data[0] == 0 && data[1] == 0 && data[2] == 1) { if (data && IS_MPEG_HEADER (data)) {
int sc = data[3]; int sc = data[3];
if (sc == 0xB0) /* visual_object_sequence_start_code */ if (sc == 0xB0) /* visual_object_sequence_start_code */
@ -1468,7 +1508,7 @@ mpeg_video_type_find (GstTypeFind * tf, gpointer unused)
gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion", gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
G_TYPE_INT, 1, NULL); G_TYPE_INT, 1, NULL);
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 1, caps); gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, caps);
gst_caps_unref (caps); gst_caps_unref (caps);
} }
} }
@ -1514,25 +1554,33 @@ mpeg_video_stream_type_find (GstTypeFind * tf, gpointer unused)
size = GST_MPEGVID_TYPEFIND_SYNC_SIZE; size = GST_MPEGVID_TYPEFIND_SYNC_SIZE;
} }
/* are we a sequence (0xB3) or GOP (0xB8) header? */ if (IS_MPEG_HEADER (data)) {
if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x1 && /* An MPEG PACK header indicates that this isn't an elementary stream */
(data[3] == 0xB3 || data[3] == 0xB8)) { if (IS_MPEG_PACK_CODE (data[3])) {
size -= 8; if (mpeg_sys_is_valid_pack (tf, data, size, NULL))
data += 8;
skipped += 8;
if (data[3] == 0xB3)
continue;
else if (size < 4) {
data = gst_type_find_peek (tf, skipped, GST_MPEGVID_TYPEFIND_SYNC_SIZE);
size = GST_MPEGVID_TYPEFIND_SYNC_SIZE;
if (!data)
break; break;
} }
/* else, we should now see an image */
/* are we a sequence (0xB3) or GOP (0xB8) header? */
if (data[3] == 0xB3 || data[3] == 0xB8) {
size -= 8;
data += 8;
skipped += 8;
if (data[3] == 0xB3)
continue;
else if (size < 4) {
data =
gst_type_find_peek (tf, skipped, GST_MPEGVID_TYPEFIND_SYNC_SIZE);
size = GST_MPEGVID_TYPEFIND_SYNC_SIZE;
if (!data)
break;
}
/* else, we should now see an image */
}
} }
/* image header (and, when found, slice header) */ /* image header (and, when found, slice header) */
if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x1 && data[4] == 0x0) { if (IS_MPEG_HEADER (data) && data[4] == 0x0) {
size -= 8; size -= 8;
data += 8; data += 8;
skipped += 8; skipped += 8;
@ -1542,10 +1590,8 @@ mpeg_video_stream_type_find (GstTypeFind * tf, gpointer unused)
if (!data) if (!data)
break; break;
} }
if ((data[0] == 0x0 && data[1] == 0x0 && if ((IS_MPEG_HEADER (data) && data[3] == 0x1) ||
data[2] == 0x1 && data[3] == 0x1) || (IS_MPEG_HEADER (data + 1) && data[4] == 0x1)) {
(data[1] == 0x0 && data[2] == 0x0 &&
data[3] == 0x1 && data[4] == 0x1)) {
size -= 4; size -= 4;
data += 4; data += 4;
skipped += 4; skipped += 4;
@ -2823,15 +2869,13 @@ plugin_init (GstPlugin * plugin)
mp3_exts, MP3_CAPS, NULL, NULL); mp3_exts, MP3_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "audio/x-ac3", GST_RANK_PRIMARY, ac3_type_find, TYPE_FIND_REGISTER (plugin, "audio/x-ac3", GST_RANK_PRIMARY, ac3_type_find,
ac3_exts, AC3_CAPS, NULL, NULL); ac3_exts, AC3_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "video/mpeg1", GST_RANK_PRIMARY, TYPE_FIND_REGISTER (plugin, "video/mpeg-sys", GST_RANK_PRIMARY,
mpeg1_sys_type_find, mpeg_sys_exts, MPEG_SYS_CAPS, NULL, NULL); mpeg_sys_type_find, mpeg_sys_exts, MPEG_SYS_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "video/mpeg2", GST_RANK_SECONDARY,
mpeg2_sys_type_find, mpeg_sys_exts, MPEG_SYS_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "video/mpegts", GST_RANK_PRIMARY, TYPE_FIND_REGISTER (plugin, "video/mpegts", GST_RANK_PRIMARY,
mpeg_ts_type_find, mpeg_ts_exts, MPEGTS_CAPS, NULL, NULL); mpeg_ts_type_find, mpeg_ts_exts, MPEGTS_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "application/ogg", GST_RANK_PRIMARY, TYPE_FIND_REGISTER (plugin, "application/ogg", GST_RANK_PRIMARY,
ogganx_type_find, ogg_exts, OGGANX_CAPS, NULL, NULL); ogganx_type_find, ogg_exts, OGGANX_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "video/mpeg", GST_RANK_SECONDARY, TYPE_FIND_REGISTER (plugin, "video/mpeg,elementary", GST_RANK_SECONDARY,
mpeg_video_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL, NULL); mpeg_video_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL, NULL);
TYPE_FIND_REGISTER (plugin, "video/mpeg-stream", GST_RANK_MARGINAL, TYPE_FIND_REGISTER (plugin, "video/mpeg-stream", GST_RANK_MARGINAL,
mpeg_video_stream_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL, mpeg_video_stream_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL,