X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Ftypefind%2Fgsttypefindfunctions.c;h=5f3c227468cca83dcfc545ff2b43280714f13bd4;hb=9791f0aaf164828df7e112ca23ccd88ba0a7f45c;hp=b9dd5d9cd1a965e72a3fd4e49dd47052ecee1479;hpb=3fab57b5cf84180cbf95600071349e19214a9df0;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c index b9dd5d9..5f3c227 100644 --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -17,8 +17,8 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H @@ -41,10 +41,15 @@ #include #include +#include GST_DEBUG_CATEGORY_STATIC (type_find_debug); #define GST_CAT_DEFAULT type_find_debug +/* so our code stays ready for 0.11 */ +#define gst_type_find_peek(tf,off,len) \ + ((const guint8 *)gst_type_find_peek((tf),(off),(len))) + /* DataScanCtx: helper for typefind functions that scan through data * step-by-step, to avoid doing a peek at each and every offset */ @@ -202,6 +207,161 @@ utf8_type_find (GstTypeFind * tf, gpointer unused) gst_type_find_suggest (tf, (start_prob + mid_prob) / 2, UTF8_CAPS); } +/*** text/utf-16 and text/utf-32} ***/ +/* While UTF-8 is unicode too, using text/plain for UTF-16 and UTF-32 + is going to break stuff. */ + +typedef struct +{ + size_t bomlen; + const char *const bom; + gboolean (*checker) (const guint8 *, gint, gint); + int boost; + int endianness; +} GstUnicodeTester; + +static gboolean +check_utf16 (const guint8 * data, gint len, gint endianness) +{ + GstByteReader br; + guint16 high, low; + + low = high = 0; + + if (len & 1) + return FALSE; + + gst_byte_reader_init (&br, data, len); + while (len >= 2) { + /* test first for a single 16 bit value in the BMP */ + if (endianness == G_BIG_ENDIAN) + high = gst_byte_reader_get_uint16_be_unchecked (&br); + else + high = gst_byte_reader_get_uint16_le_unchecked (&br); + if (high >= 0xD800 && high <= 0xDBFF) { + /* start of a surrogate pair */ + if (len < 4) + return FALSE; + len -= 2; + if (endianness == G_BIG_ENDIAN) + low = gst_byte_reader_get_uint16_be_unchecked (&br); + else + low = gst_byte_reader_get_uint16_le_unchecked (&br); + if (low >= 0xDC00 && low <= 0xDFFF) { + /* second half of the surrogate pair */ + } else + return FALSE; + } else { + if (high >= 0xDC00 && high <= 0xDFFF) + return FALSE; + } + len -= 2; + } + return TRUE; +} + +static gboolean +check_utf32 (const guint8 * data, gint len, gint endianness) +{ + if (len & 3) + return FALSE; + while (len > 3) { + guint32 v; + if (endianness == G_BIG_ENDIAN) + v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + else + v = (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0]; + if (v >= 0x10FFFF) + return FALSE; + data += 4; + len -= 4; + } + return TRUE; +} + +static void +unicode_type_find (GstTypeFind * tf, const GstUnicodeTester * tester, + guint n_tester, const char *media_type, gboolean require_bom) +{ + size_t n; + gint len = 4; + const guint8 *data = gst_type_find_peek (tf, 0, len); + int prob = -1; + const gint max_scan_size = 256 * 1024; + int endianness = 0; + + if (!data) { + len = 2; + data = gst_type_find_peek (tf, 0, len); + if (!data) + return; + } + + /* find a large enough size that works */ + while (len < max_scan_size) { + size_t newlen = len << 1; + const guint8 *newdata = gst_type_find_peek (tf, 0, newlen); + if (!newdata) + break; + len = newlen; + data = newdata; + } + + for (n = 0; n < n_tester; ++n) { + int bom_boost = 0, tmpprob; + if (len >= tester[n].bomlen) { + if (!memcmp (data, tester[n].bom, tester[n].bomlen)) + bom_boost = tester[n].boost; + } + if (require_bom && bom_boost == 0) + continue; + if (!(*tester[n].checker) (data, len, tester[n].endianness)) + continue; + tmpprob = GST_TYPE_FIND_POSSIBLE - 20 + bom_boost; + if (tmpprob > prob) { + prob = tmpprob; + endianness = tester[n].endianness; + } + } + + if (prob > 0) { + GST_DEBUG ("This is valid %s %s", media_type, + endianness == G_BIG_ENDIAN ? "be" : "le"); + gst_type_find_suggest_simple (tf, prob, media_type, + "endianness", G_TYPE_INT, endianness, NULL); + } +} + +static GstStaticCaps utf16_caps = GST_STATIC_CAPS ("text/utf-16"); + +#define UTF16_CAPS gst_static_caps_get(&utf16_caps) + +static void +utf16_type_find (GstTypeFind * tf, gpointer unused) +{ + static const GstUnicodeTester utf16tester[2] = { + {2, "\xff\xfe", check_utf16, 10, G_LITTLE_ENDIAN}, + {2, "\xfe\xff", check_utf16, 20, G_BIG_ENDIAN}, + }; + unicode_type_find (tf, utf16tester, G_N_ELEMENTS (utf16tester), + "text/utf-16", TRUE); +} + +static GstStaticCaps utf32_caps = GST_STATIC_CAPS ("text/utf-32"); + +#define UTF32_CAPS gst_static_caps_get(&utf32_caps) + +static void +utf32_type_find (GstTypeFind * tf, gpointer unused) +{ + static const GstUnicodeTester utf32tester[2] = { + {4, "\xff\xfe\x00\x00", check_utf32, 10, G_LITTLE_ENDIAN}, + {4, "\x00\x00\xfe\xff", check_utf32, 20, G_BIG_ENDIAN} + }; + unicode_type_find (tf, utf32tester, G_N_ELEMENTS (utf32tester), + "text/utf-32", TRUE); +} + /*** text/uri-list ***/ static GstStaticCaps uri_caps = GST_STATIC_CAPS ("text/uri-list"); @@ -685,6 +845,90 @@ flac_type_find (GstTypeFind * tf, gpointer unused) #endif } +/* TODO: we could probably make a generic function for this.. */ +static gint +aac_type_find_scan_loas_frames_ep (GstTypeFind * tf, DataScanCtx * scan_ctx, + gint max_frames) +{ + DataScanCtx c = *scan_ctx; + guint16 snc; + guint len; + gint count = 0; + + do { + if (!data_scan_ctx_ensure_data (tf, &c, 5)) + break; + + /* EPAudioSyncStream */ + len = ((c.data[2] & 0x0f) << 9) | (c.data[3] << 1) | + ((c.data[4] & 0x80) >> 7); + + if (len == 0 || !data_scan_ctx_ensure_data (tf, &c, len + 2)) { + GST_DEBUG ("Wrong sync or next frame not within reach, len=%u", len); + break; + } + + /* check length of frame */ + snc = GST_READ_UINT16_BE (c.data + len); + if (snc != 0x4de1) { + GST_DEBUG ("No sync found at 0x%" G_GINT64_MODIFIER "x", c.offset + len); + break; + } + + ++count; + + GST_DEBUG ("Found LOAS syncword #%d at offset 0x%" G_GINT64_MODIFIER "x, " + "framelen %u", count, c.offset, len); + + data_scan_ctx_advance (tf, &c, len); + } while (count < max_frames && (c.offset - scan_ctx->offset) < 64 * 1024); + + GST_DEBUG ("found %d consecutive frames", count); + return count; +} + +static gint +aac_type_find_scan_loas_frames (GstTypeFind * tf, DataScanCtx * scan_ctx, + gint max_frames) +{ + DataScanCtx c = *scan_ctx; + guint16 snc; + guint len; + gint count = 0; + + do { + if (!data_scan_ctx_ensure_data (tf, &c, 3)) + break; + + /* AudioSyncStream */ + len = ((c.data[1] & 0x1f) << 8) | c.data[2]; + /* add size of sync stream header */ + len += 3; + + if (len == 0 || !data_scan_ctx_ensure_data (tf, &c, len)) { + GST_DEBUG ("Wrong sync or next frame not within reach, len=%u", len); + break; + } + + /* check length of frame */ + snc = GST_READ_UINT16_BE (c.data + len); + if ((snc & 0xffe0) != 0x56e0) { + GST_DEBUG ("No sync found at 0x%" G_GINT64_MODIFIER "x", c.offset + len); + break; + } + + ++count; + + GST_DEBUG ("Found LOAS syncword #%d at offset 0x%" G_GINT64_MODIFIER "x, " + "framelen %u", count, c.offset, len); + + data_scan_ctx_advance (tf, &c, len); + } while (count < max_frames && (c.offset - scan_ctx->offset) < 64 * 1024); + + GST_DEBUG ("found %d consecutive frames", count); + return count; +} + /*** audio/mpeg version 2, 4 ***/ static GstStaticCaps aac_caps = GST_STATIC_CAPS ("audio/mpeg, " @@ -694,8 +938,10 @@ static GstStaticCaps aac_caps = GST_STATIC_CAPS ("audio/mpeg, " static void aac_type_find (GstTypeFind * tf, gpointer unused) { - /* LUT to convert the AudioObjectType from the ADTS header to a string */ DataScanCtx c = { 0, NULL, 0 }; + GstTypeFindProbability best_probability = GST_TYPE_FIND_NONE; + GstCaps *best_caps = NULL; + guint best_count = 0; while (c.offset < AAC_AMOUNT) { guint snc, len; @@ -781,45 +1027,29 @@ aac_type_find (GstTypeFind * tf, gpointer unused) } GST_DEBUG ("No next frame found... (should have been at 0x%x)", len); - } else if (G_UNLIKELY (((snc & 0xffe0) == 0x56e0) || (snc == 0x4de1))) { - /* LOAS frame */ - - GST_DEBUG ("Found one LOAS syncword at offset 0x%" G_GINT64_MODIFIER - "x, tracing next...", c.offset); + } else if (G_UNLIKELY ((snc & 0xffe0) == 0x56e0 || snc == 0x4de1)) { + gint count; - /* check length of frame for each type of detectable LOAS streams */ - if (snc == 0x4de1) { - /* EPAudioSyncStream */ - len = ((c.data[2] & 0x0f) << 9) | (c.data[3] << 1) | - ((c.data[4] & 0x80) >> 7); - /* add size of EP sync stream header */ - len += 7; - } else { - /* AudioSyncStream */ - len = ((c.data[1] & 0x1f) << 8) | c.data[2]; - /* add size of sync stream header */ - len += 3; - } - - if (len == 0 || !data_scan_ctx_ensure_data (tf, &c, len + 2)) { - GST_DEBUG ("Wrong sync or next frame not within reach, len=%u", len); - goto next; - } + /* LOAS frame */ + GST_INFO ("Possible LOAS syncword at offset 0x%" G_GINT64_MODIFIER + "x, scanning for more frames...", c.offset); - /* check if there's a second LOAS frame */ - snc = GST_READ_UINT16_BE (c.data + len); - if (((snc & 0xffe0) == 0x56e0) || (snc == 0x4de1)) { - GST_DEBUG ("Found second LOAS syncword at offset 0x%" - G_GINT64_MODIFIER "x, framelen %u", c.offset, len); + if (snc == 0x4de1) + count = aac_type_find_scan_loas_frames_ep (tf, &c, 20); + else + count = aac_type_find_scan_loas_frames (tf, &c, 20); - gst_type_find_suggest_simple (tf, GST_TYPE_FIND_LIKELY, "audio/mpeg", + if (count >= 3 && count > best_count) { + gst_caps_replace (&best_caps, NULL); + best_caps = gst_caps_new_simple ("audio/mpeg", "framed", G_TYPE_BOOLEAN, FALSE, "mpegversion", G_TYPE_INT, 4, "stream-format", G_TYPE_STRING, "loas", NULL); - break; + best_count = count; + best_probability = GST_TYPE_FIND_POSSIBLE - 10 + count * 3; + if (best_probability >= GST_TYPE_FIND_LIKELY) + break; } - - GST_DEBUG ("No next frame found... (should have been at 0x%x)", len); } else if (!memcmp (c.data, "ADIF", 4)) { /* ADIF header */ gst_type_find_suggest_simple (tf, GST_TYPE_FIND_LIKELY, "audio/mpeg", @@ -832,6 +1062,11 @@ aac_type_find (GstTypeFind * tf, gpointer unused) data_scan_ctx_advance (tf, &c, 1); } + + if (best_probability > GST_TYPE_FIND_NONE) { + gst_type_find_suggest (tf, best_probability, best_caps); + gst_caps_unref (best_caps); + } } /*** audio/mpeg version 1 ***/ @@ -903,7 +1138,7 @@ mp3_type_frame_length_from_header (guint32 header, guint * put_layer, /* bitrate index */ bitrate = header & 0xF; if (bitrate == 0 && possible_free_framelen == -1) { - GST_LOG ("Possibly a free format mp3 - signalling"); + GST_LOG ("Possibly a free format mp3 - signaling"); *may_be_free_format = TRUE; } if (bitrate == 15 || (bitrate == 0 && possible_free_framelen == -1)) @@ -1185,7 +1420,8 @@ suggest: g_return_if_fail (layer >= 1 && layer <= 3); gst_type_find_suggest_simple (tf, prob, "audio/mpeg", - "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, layer, NULL); + "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, layer, + "parsed", G_TYPE_BOOLEAN, FALSE, NULL); } } @@ -1282,7 +1518,7 @@ ac3_type_find (GstTypeFind * tf, gpointer unused) { DataScanCtx c = { 0, NULL, 0 }; - /* Search for an ac3 frame; not neccesarily right at the start, but give it + /* Search for an ac3 frame; not necessarily right at the start, but give it * a lower probability if not found right at the start. Check that the * frame is followed by a second frame at the expected offset. * We could also check the two ac3 CRCs, but we don't do that right now */ @@ -1449,7 +1685,7 @@ dts_type_find (GstTypeFind * tf, gpointer unused) { DataScanCtx c = { 0, NULL, 0 }; - /* Search for an dts frame; not neccesarily right at the start, but give it + /* Search for an dts frame; not necessarily right at the start, but give it * a lower probability if not found right at the start. Check that the * frame is followed by a second frame at the expected offset. */ while (c.offset <= DTS_MAX_FRAMESIZE) { @@ -1518,9 +1754,11 @@ GST_STATIC_CAPS ("audio/x-wavpack-correction, framed = (boolean) false"); static void wavpack_type_find (GstTypeFind * tf, gpointer unused) { + GstTypeFindProbability base_prob = GST_TYPE_FIND_POSSIBLE; guint64 offset; guint32 blocksize; const guint8 *data; + guint count_wv, count_wvc; data = gst_type_find_peek (tf, 0, 32); if (!data) @@ -1535,8 +1773,10 @@ wavpack_type_find (GstTypeFind * tf, gpointer unused) * work in pull-mode */ blocksize = GST_READ_UINT32_LE (data + 4); GST_LOG ("wavpack header, blocksize=0x%04x", blocksize); + count_wv = 0; + count_wvc = 0; offset = 32; - while (offset < 32 + blocksize) { + while (offset < 8 + blocksize) { guint32 sublen; /* get chunk header */ @@ -1551,7 +1791,7 @@ wavpack_type_find (GstTypeFind * tf, gpointer unused) } else { sublen += 1 + 1; /* id + length */ } - if (sublen > blocksize - offset + 32) { + if (offset + sublen > 8 + blocksize) { GST_LOG ("chunk length too big (%u > %" G_GUINT64_FORMAT ")", sublen, blocksize - offset); break; @@ -1560,18 +1800,38 @@ wavpack_type_find (GstTypeFind * tf, gpointer unused) switch (data[0] & 0x0f) { case 0xa: /* ID_WV_BITSTREAM */ case 0xc: /* ID_WVX_BITSTREAM */ - gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, WAVPACK_CAPS); - return; + ++count_wv; + break; case 0xb: /* ID_WVC_BITSTREAM */ - gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, - WAVPACK_CORRECTION_CAPS); - return; + ++count_wvc; + break; default: break; } + if (count_wv >= 5 || count_wvc >= 5) + break; } offset += sublen; } + + /* check for second block header */ + data = gst_type_find_peek (tf, 8 + blocksize, 4); + if (data != NULL && memcmp (data, "wvpk", 4) == 0) { + GST_DEBUG ("found second block sync"); + base_prob = GST_TYPE_FIND_LIKELY; + } + + GST_DEBUG ("wvc=%d, wv=%d", count_wvc, count_wv); + + if (count_wvc > 0 && count_wvc > count_wv) { + gst_type_find_suggest (tf, + MIN (base_prob + 5 * count_wvc, GST_TYPE_FIND_NEARLY_CERTAIN), + WAVPACK_CORRECTION_CAPS); + } else if (count_wv > 0) { + gst_type_find_suggest (tf, + MIN (base_prob + 5 * count_wv, GST_TYPE_FIND_NEARLY_CERTAIN), + WAVPACK_CAPS); + } } /*** application/postscrip ***/ @@ -2242,6 +2502,10 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) /* Stream consists of: a series of sync codes (00 00 00 01) followed * by NALs */ + gboolean seen_idr = FALSE; + gboolean seen_sps = FALSE; + gboolean seen_pps = FALSE; + gboolean seen_ssps = FALSE; int nut, ref; int good = 0; int bad = 0; @@ -2254,7 +2518,7 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) nut = c.data[3] & 0x9f; /* forbiden_zero_bit | nal_unit_type */ ref = c.data[3] & 0x60; /* nal_ref_idc */ - /* if forbiden bit is different to 0 won't be h264 */ + /* if forbidden bit is different to 0 won't be h264 */ if (nut > 0x1f) { bad++; break; @@ -2266,22 +2530,37 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) ((nut == 6 || (nut >= 9 && nut <= 12)) && ref != 0)) { bad++; } else { + if (nut == 7) + seen_sps = TRUE; + else if (nut == 8) + seen_pps = TRUE; + else if (nut == 5) + seen_idr = TRUE; + good++; } } else if (nut >= 14 && nut <= 33) { - /* reserved */ - /* Theoretically these are good, since if they exist in the - stream it merely means that a newer backwards-compatible - h.264 stream. But we should be identifying that separately. */ - bad++; + if (nut == 15) { + seen_ssps = TRUE; + good++; + } else if (seen_ssps && (nut == 14 || nut == 20)) { + good++; + } else { + /* reserved */ + /* Theoretically these are good, since if they exist in the + stream it merely means that a newer backwards-compatible + h.264 stream. But we should be identifying that separately. */ + bad++; + } } else { /* unspecified, application specific */ /* don't consider these bad */ } - GST_DEBUG ("good %d bad %d", good, bad); + GST_LOG ("good:%d, bad:%d, pps:%d, sps:%d, idr:%d ssps:%d", good, bad, + seen_pps, seen_sps, seen_idr, seen_ssps); - if (good >= 10 && bad < 4) { + if (seen_sps && seen_pps && seen_idr && good >= 10 && bad < 4) { gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, H264_VIDEO_CAPS); return; } @@ -2291,9 +2570,11 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) data_scan_ctx_advance (tf, &c, 1); } - if (good >= 2 && bad < 1) { + GST_LOG ("good:%d, bad:%d, pps:%d, sps:%d, idr:%d ssps=%d", good, bad, + seen_pps, seen_sps, seen_idr, seen_ssps); + + if (good >= 2 && bad == 0) { gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, H264_VIDEO_CAPS); - return; } } @@ -2401,7 +2682,7 @@ mpeg_video_stream_type_find (GstTypeFind * tf, gpointer unused) gst_type_find_suggest_simple (tf, probability, "video/mpeg", "systemstream", G_TYPE_BOOLEAN, FALSE, - "mpegversion", G_TYPE_INT, 1, NULL); + "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, FALSE, NULL); } } @@ -2623,6 +2904,12 @@ qt_type_find (GstTypeFind * tf, gpointer unused) break; } + if (STRNCMP (&data[4], "ftypisml", 8) == 0) { + tip = GST_TYPE_FIND_MAXIMUM; + variant = "iso-fragmented"; + break; + } + /* box/atom types that are in common with ISO base media file format */ if (STRNCMP (&data[4], "moov", 4) == 0 || STRNCMP (&data[4], "mdat", 4) == 0 || @@ -2887,6 +3174,13 @@ mod_type_find (GstTypeFind * tf, gpointer unused) return; } } + /* AMF */ + if ((data = gst_type_find_peek (tf, 0, 19)) != NULL) { + if (memcmp (data, "ASYLUM Music Format", 19) == 0) { + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MOD_CAPS); + return; + } + } } /*** application/x-shockwave-flash ***/ @@ -3001,7 +3295,9 @@ jpeg_type_find (GstTypeFind * tf, gpointer unused) prob = GST_TYPE_FIND_LIKELY; gst_caps_set_simple (caps, "width", G_TYPE_INT, w, - "height", G_TYPE_INT, h, NULL); + "height", G_TYPE_INT, h, "sof-marker", G_TYPE_INT, marker & 0xf, + NULL); + break; } else { GST_WARNING ("bad length or unexpected JPEG marker 0xff 0x%02x", marker); @@ -3253,76 +3549,256 @@ ircam_type_find (GstTypeFind * tf, gpointer ununsed) } } -/* EBML typefind helper */ -static gboolean -ebml_check_header (GstTypeFind * tf, const gchar * doctype, int doctype_len) +/*** Matroska/WebM ***/ + +#define EBML_HEADER 0x1A45DFA3 +#define EBML_VERSION 0x4286 +#define EBML_DOCTYPE 0x4282 +#define EBML_DOCTYPE_VERSION 0x4287 +#define MATROSKA_SEGMENT 0x18538067 +#define MATROSKA_CLUSTER 0x1F43B675 +#define MATROSKA_TRACKS 0x1654AE6B +#define MATROSKA_TRACK_ENTRY 0xAE +#define MATROSKA_TRACK_TYPE 0x83 +#define MATROSKA_STEREO_MODE 0x53B8 + +#define EBML_MAX_LEN (2 * 1024 * 1024) + +typedef enum { - /* 4 bytes for EBML ID, 1 byte for header length identifier */ - const guint8 *data = gst_type_find_peek (tf, 0, 4 + 1); - gint len_mask = 0x80, size = 1, n = 1, total; + EBML_DOCTYPE_UNKNOWN = 0, + EBML_DOCTYPE_MATROSKA, + EBML_DOCTYPE_WEBM +} GstEbmlDocType; - if (!data) - return FALSE; +typedef struct +{ + GstEbmlDocType doctype; + guint audio; + guint video; + guint other; + guint video_stereo; + guint chunks; + guint tracks_ok; /* if we've seen and fully parsed the TRACKS element */ +} GstMatroskaInfo; - /* ebml header? */ - if (data[0] != 0x1A || data[1] != 0x45 || data[2] != 0xDF || data[3] != 0xA3) - return FALSE; +static inline guint +ebml_read_chunk_header (GstTypeFind * tf, DataScanCtx * c, guint max_size, + guint32 * id, guint64 * size) +{ + guint64 mask; + guint msbit_set, i, len, id_len; - /* length of header */ - total = data[4]; - while (size <= 8 && !(total & len_mask)) { - size++; - len_mask >>= 1; + if (c->size < 12 || max_size < 1) + return 0; + + /* element ID */ + *id = c->data[0]; + if ((c->data[0] & 0x80) == 0x80) { + id_len = 1; + } else if ((c->data[0] & 0xC0) == 0x40) { + id_len = 2; + } else if ((c->data[0] & 0xE0) == 0x20) { + id_len = 3; + } else if ((c->data[0] & 0xF0) == 0x10) { + id_len = 4; + } else { + return 0; } - if (size > 8) - return FALSE; - total &= (len_mask - 1); - while (n < size) - total = (total << 8) | data[4 + n++]; - /* get new data for full header, 4 bytes for EBML ID, - * EBML length tag and the actual header */ - data = gst_type_find_peek (tf, 0, 4 + size + total); - if (!data) + if (max_size < id_len) + return 0; + + for (i = 1; i < id_len; ++i) { + *id = (*id << 8) | c->data[i]; + } + + data_scan_ctx_advance (tf, c, id_len); + max_size -= id_len; + + /* size */ + if (max_size < 1 || c->data[0] == 0) + return 0; + + msbit_set = g_bit_nth_msf (c->data[0], 8); + mask = ((1 << msbit_set) - 1); + *size = c->data[0] & mask; + len = 7 - msbit_set; + + if (max_size < 1 + len) + return 0; + for (i = 0; i < len; ++i) { + mask = (mask << 8) | 0xff; + *size = (*size << 8) | c->data[1 + i]; + } + + data_scan_ctx_advance (tf, c, 1 + len); + + /* undefined/unknown size? (all bits 1) */ + if (*size == mask) { + /* allow unknown size for SEGMENT chunk, bail out otherwise */ + if (*id == MATROSKA_SEGMENT) + *size = G_MAXUINT64; + else + return 0; + } + + return id_len + (1 + len); +} + +static gboolean +ebml_parse_chunk (GstTypeFind * tf, DataScanCtx * ctx, guint32 chunk_id, + guint chunk_size, GstMatroskaInfo * info, guint depth) +{ /* FIXME: make sure input size is clipped to 32 bit */ + static const gchar SPACES[] = " "; + DataScanCtx c = *ctx; + guint64 element_size; + guint32 id, hdr_len; + + if (depth >= 8) /* keep SPACES large enough for depth */ return FALSE; - /* only check doctype if asked to do so */ - if (doctype == NULL || doctype_len == 0) - return TRUE; + while (chunk_size > 0) { + if (c.offset > EBML_MAX_LEN || !data_scan_ctx_ensure_data (tf, &c, 64)) + return FALSE; - /* the header must contain the doctype. For now, we don't parse the - * whole header but simply check for the availability of that array - * of characters inside the header. Not fully fool-proof, but good - * enough. */ - for (n = 4 + size; n <= 4 + size + total - doctype_len; n++) - if (!memcmp (&data[n], doctype, doctype_len)) - return TRUE; + hdr_len = ebml_read_chunk_header (tf, &c, chunk_size, &id, &element_size); + if (hdr_len == 0) + return FALSE; - return FALSE; + g_assert (hdr_len <= chunk_size); + chunk_size -= hdr_len; + + if (element_size > chunk_size) + return FALSE; + + GST_DEBUG ("%s %08x, size %" G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT, + SPACES + sizeof (SPACES) - 1 - (2 * depth), id, element_size, + hdr_len + element_size); + + if (!data_scan_ctx_ensure_data (tf, &c, element_size)) { + GST_DEBUG ("not enough data"); + return FALSE; + } + + switch (id) { + case EBML_DOCTYPE: + if (element_size >= 8 && memcmp (c.data, "matroska", 8) == 0) + info->doctype = EBML_DOCTYPE_MATROSKA; + else if (element_size >= 4 && memcmp (c.data, "webm", 4) == 0) + info->doctype = EBML_DOCTYPE_WEBM; + break; + case MATROSKA_SEGMENT: + GST_LOG ("parsing segment"); + ebml_parse_chunk (tf, &c, id, element_size, info, depth + 1); + GST_LOG ("parsed segment, done"); + return FALSE; + case MATROSKA_TRACKS: + GST_LOG ("parsing tracks"); + info->tracks_ok = + ebml_parse_chunk (tf, &c, id, element_size, info, depth + 1); + GST_LOG ("parsed tracks: %s, done (after %" G_GUINT64_FORMAT " bytes)", + info->tracks_ok ? "ok" : "FAIL", c.offset + element_size); + return FALSE; + case MATROSKA_TRACK_ENTRY: + GST_LOG ("parsing track entry"); + if (!ebml_parse_chunk (tf, &c, id, element_size, info, depth + 1)) + return FALSE; + break; + case MATROSKA_TRACK_TYPE:{ + guint type = 0, i; + + /* is supposed to always be 1-byte, but not everyone's following that */ + for (i = 0; i < element_size; ++i) + type = (type << 8) | c.data[i]; + + GST_DEBUG ("%s track type %u", + SPACES + sizeof (SPACES) - 1 - (2 * depth), type); + + if (type == 1) + ++info->video; + else if (c.data[0] == 2) + ++info->audio; + else + ++info->other; + break; + } + case MATROSKA_STEREO_MODE: + ++info->video_stereo; + break; + case MATROSKA_CLUSTER: + GST_WARNING ("cluster, bailing out (should've found tracks by now)"); + return FALSE; + default: + break; + } + data_scan_ctx_advance (tf, &c, element_size); + chunk_size -= element_size; + ++info->chunks; + } + + return TRUE; } -/*** video/x-matroska ***/ static GstStaticCaps matroska_caps = GST_STATIC_CAPS ("video/x-matroska"); #define MATROSKA_CAPS (gst_static_caps_get(&matroska_caps)) static void matroska_type_find (GstTypeFind * tf, gpointer ununsed) { - if (ebml_check_header (tf, "matroska", 8)) - gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MATROSKA_CAPS); - else if (ebml_check_header (tf, NULL, 0)) - gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY, MATROSKA_CAPS); -} + GstTypeFindProbability prob; + GstMatroskaInfo info = { 0, }; + const gchar *type_name; + DataScanCtx c = { 0, NULL, 0 }; + gboolean is_audio; + guint64 size; + guint32 id, hdr_len; -/*** video/webm ***/ -static GstStaticCaps webm_caps = GST_STATIC_CAPS ("video/webm"); + if (!data_scan_ctx_ensure_data (tf, &c, 64)) + return; -#define WEBM_CAPS (gst_static_caps_get(&webm_caps)) -static void -webm_type_find (GstTypeFind * tf, gpointer ununsed) -{ - if (ebml_check_header (tf, "webm", 4)) - gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, WEBM_CAPS); + if (GST_READ_UINT32_BE (c.data) != EBML_HEADER) + return; + + while (c.offset < EBML_MAX_LEN && data_scan_ctx_ensure_data (tf, &c, 64)) { + hdr_len = ebml_read_chunk_header (tf, &c, c.size, &id, &size); + if (hdr_len == 0) + return; + + GST_INFO ("=== top-level chunk %08x, size %" G_GUINT64_FORMAT + " / %" G_GUINT64_FORMAT, id, size, size + hdr_len); + + if (!ebml_parse_chunk (tf, &c, id, size, &info, 0)) + break; + data_scan_ctx_advance (tf, &c, size); + GST_INFO ("=== done with chunk %08x", id); + if (id == MATROSKA_SEGMENT) + break; + } + + GST_INFO ("audio=%u video=%u other=%u chunks=%u doctype=%d all_tracks=%d", + info.audio, info.video, info.other, info.chunks, info.doctype, + info.tracks_ok); + + /* perhaps we should bail out if tracks_ok is FALSE and wait for more data? + * (we would need new API to signal this properly and prevent other + * typefinders from taking over the decision then) */ + is_audio = (info.audio > 0 && info.video == 0 && info.other == 0); + + if (info.doctype == EBML_DOCTYPE_WEBM) { + type_name = (is_audio) ? "audio/webm" : "video/webm"; + } else if (info.video > 0 && info.video_stereo) { + type_name = "video/x-matroska-3d"; + } else { + type_name = (is_audio) ? "audio/x-matroska" : "video/x-matroska"; + } + + if (info.doctype == EBML_DOCTYPE_UNKNOWN) + prob = GST_TYPE_FIND_LIKELY; + else + prob = GST_TYPE_FIND_MAXIMUM; + + gst_type_find_suggest_simple (tf, prob, type_name, NULL); } /*** application/mxf ***/ @@ -3407,30 +3883,116 @@ dv_type_find (GstTypeFind * tf, gpointer private) } -/*** application/ogg and application/x-annodex ***/ -static GstStaticCaps ogg_caps = GST_STATIC_CAPS ("application/ogg"); -static GstStaticCaps annodex_caps = GST_STATIC_CAPS ("application/x-annodex"); -static GstStaticCaps ogg_annodex_caps = - GST_STATIC_CAPS ("application/ogg;application/x-annodex"); +/*** Ogg variants ***/ +static GstStaticCaps ogg_caps = + GST_STATIC_CAPS ("application/ogg;video/ogg;audio/ogg;application/kate"); + +#define OGG_CAPS (gst_static_caps_get(&ogg_caps)) -#define OGGANX_CAPS (gst_static_caps_get(&ogg_annodex_caps)) +typedef enum +{ + OGG_AUDIO = 0, + OGG_VIDEO, + OGG_KATE, + OGG_OTHER, + OGG_SKELETON, + OGG_ANNODEX, + OGG_NUM +} GstOggStreamType; static void ogganx_type_find (GstTypeFind * tf, gpointer private) { - const guint8 *data = gst_type_find_peek (tf, 0, 4); + const gchar *media_type; + DataScanCtx c = { 0, NULL, 0 }; + guint ogg_syncs = 0; + guint hdr_count[OGG_NUM] = { 0, }; + static const struct + { + const gchar marker[10]; + guint8 marker_size; + GstOggStreamType stream_type; + } markers[] = { + { + "\001vorbis", 7, OGG_AUDIO}, { + "\200theora", 7, OGG_VIDEO}, { + "fLaC", 4, OGG_AUDIO}, { + "\177FLAC", 5, OGG_AUDIO}, { + "Speex", 5, OGG_AUDIO}, { + "CMML\0\0\0\0", 8, OGG_OTHER}, { + "PCM ", 8, OGG_AUDIO}, { + "Annodex", 7, OGG_ANNODEX}, { + "fishead", 7, OGG_SKELETON}, { + "AnxData", 7, OGG_ANNODEX}, { + "CELT ", 8, OGG_AUDIO}, { + "\200kate\0\0\0", 8, OGG_KATE}, { + "BBCD\0", 5, OGG_VIDEO}, { + "OVP80\1\1", 7, OGG_VIDEO}, { + "OpusHead", 8, OGG_AUDIO}, { + "\001audio\0\0\0", 9, OGG_AUDIO}, { + "\001video\0\0\0", 9, OGG_VIDEO}, { + "\001text\0\0\0", 9, OGG_OTHER} + }; + + while (c.offset < 4096 && data_scan_ctx_ensure_data (tf, &c, 64)) { + guint size, i; - if ((data != NULL) && (memcmp (data, "OggS", 4) == 0)) { + if (memcmp (c.data, "OggS", 5) != 0) + break; - /* Check for an annodex fishbone header */ - data = gst_type_find_peek (tf, 28, 8); - if (data && memcmp (data, "fishead\0", 8) == 0) - gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, - gst_static_caps_get (&annodex_caps)); + ++ogg_syncs; + + /* check if BOS */ + if (c.data[5] != 0x02) + break; - gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, - gst_static_caps_get (&ogg_caps)); + /* headers should only have one segment */ + if (c.data[26] != 1) + break; + + size = c.data[27]; + if (size < 8) + break; + + data_scan_ctx_advance (tf, &c, 28); + + if (!data_scan_ctx_ensure_data (tf, &c, MAX (size, 8))) + break; + + for (i = 0; i < G_N_ELEMENTS (markers); ++i) { + if (memcmp (c.data, markers[i].marker, markers[i].marker_size) == 0) { + ++hdr_count[markers[i].stream_type]; + break; + } + } + + if (i == G_N_ELEMENTS (markers)) { + GST_MEMDUMP ("unknown Ogg stream marker", c.data, size); + ++hdr_count[OGG_OTHER]; + } + + data_scan_ctx_advance (tf, &c, size); + } + + if (ogg_syncs == 0) + return; + + /* We don't bother with annodex types. FIXME: what about XSPF? */ + if (hdr_count[OGG_VIDEO] > 0) { + media_type = "video/ogg"; + } else if (hdr_count[OGG_AUDIO] > 0) { + media_type = "audio/ogg"; + } else if (hdr_count[OGG_KATE] > 0 && hdr_count[OGG_OTHER] == 0) { + media_type = "application/kate"; + } else { + media_type = "application/ogg"; } + + GST_INFO ("found %s (audio:%u, video:%u, annodex:%u, skeleton:%u, other:%u)", + media_type, hdr_count[OGG_AUDIO], hdr_count[OGG_VIDEO], + hdr_count[OGG_ANNODEX], hdr_count[OGG_SKELETON], hdr_count[OGG_OTHER]); + + gst_type_find_suggest_simple (tf, GST_TYPE_FIND_MAXIMUM, media_type, NULL); } /*** audio/x-vorbis ***/ @@ -3788,6 +4350,66 @@ paris_type_find (GstTypeFind * tf, gpointer unused) } } +/*** audio/x-sbc ***/ +static GstStaticCaps sbc_caps = GST_STATIC_CAPS ("audio/x-sbc"); +#define SBC_CAPS (gst_static_caps_get(&sbc_caps)) + +static gsize +sbc_check_header (const guint8 * data, gsize len, guint * rate, + guint * channels) +{ + static const guint16 sbc_rates[4] = { 16000, 32000, 44100, 48000 }; + static const guint8 sbc_blocks[4] = { 4, 8, 12, 16 }; + guint n_blocks, ch_mode, n_subbands, bitpool; + + if (data[0] != 0x9C || len < 4) + return 0; + + n_blocks = sbc_blocks[(data[1] >> 4) & 0x03]; + ch_mode = (data[1] >> 2) & 0x03; + n_subbands = (data[1] & 0x01) ? 8 : 4; + bitpool = data[2]; + if (bitpool < 2) + return 0; + + *rate = sbc_rates[(data[1] >> 6) & 0x03]; + *channels = (ch_mode == 0) ? 1 : 2; + + if (ch_mode == 0) + return 4 + (n_subbands * 1) / 2 + (n_blocks * 1 * bitpool) / 8; + else if (ch_mode == 1) + return 4 + (n_subbands * 2) / 2 + (n_blocks * 2 * bitpool) / 8; + else if (ch_mode == 2) + return 4 + (n_subbands * 2) / 2 + (n_blocks * bitpool) / 8; + else if (ch_mode == 3) + return 4 + (n_subbands * 2) / 2 + (n_subbands + n_blocks * bitpool) / 8; + + return 0; +} + +static void +sbc_type_find (GstTypeFind * tf, gpointer unused) +{ + const guint8 *data; + gsize frame_len; + guint i, rate, channels, offset = 0; + + for (i = 0; i < 10; ++i) { + data = gst_type_find_peek (tf, offset, 8); + if (data == NULL) + return; + + frame_len = sbc_check_header (data, 8, &rate, &channels); + if (frame_len == 0) + return; + + offset += frame_len; + } + gst_type_find_suggest_simple (tf, GST_TYPE_FIND_POSSIBLE, "audio/x-sbc", + "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, + "parsed", G_TYPE_BOOLEAN, FALSE, NULL); +} + /*** audio/iLBC-sh ***/ /* NOTE: do not replace this function with two TYPE_FIND_REGISTER_START_WITH */ static GstStaticCaps ilbc_caps = GST_STATIC_CAPS ("audio/iLBC-sh"); @@ -4120,6 +4742,119 @@ degas_type_find (GstTypeFind * tf, gpointer private) } } +/*** DVD ISO images (looks like H.264, see #674069) ***/ +static void +dvdiso_type_find (GstTypeFind * tf, gpointer private) +{ + /* 0x8000 bytes of zeros, then "\001CD001" */ + gint64 len; + const guint8 *data; + + len = gst_type_find_get_length (tf); + if (len < 0x8006) + return; + data = gst_type_find_peek (tf, 0, 0x8006); + if (G_UNLIKELY (data == NULL)) + return; + for (len = 0; len < 0x8000; len++) + if (data[len]) + return; + /* Can the '1' be anything else ? My three samples all have '1'. */ + if (memcmp (data + 0x8000, "\001CD001", 6)) + return; + + /* May need more inspection, we may be able to demux some of them */ + gst_type_find_suggest_simple (tf, GST_TYPE_FIND_LIKELY, + "application/octet-stream", NULL); +} + +/* SSA/ASS subtitles + * + * http://en.wikipedia.org/wiki/SubStation_Alpha + * http://matroska.org/technical/specs/subtitles/ssa.html + */ +static void +ssa_type_find (GstTypeFind * tf, gpointer private) +{ + const gchar *start, *end, *ver_str, *media_type = NULL; + const guint8 *data; + gchar *str, *script_type, *p = NULL; + gint64 len; + + data = gst_type_find_peek (tf, 0, 32); + + if (data == NULL) + return; + + /* there might be a BOM at the beginning */ + if (memcmp (data, "[Script Info]", 13) != 0 && + memcmp (data + 2, "[Script Info]", 13) != 0 && + memcmp (data + 3, "[Script Info]", 13) != 0 && + memcmp (data + 4, "[Script Info]", 13) != 0) { + return; + } + + /* now check if we have SSA or ASS */ + len = gst_type_find_get_length (tf); + if (len > 8192) + len = 8192; + + data = gst_type_find_peek (tf, 0, len); + if (data == NULL) + return; + + /* skip BOM */ + start = (gchar *) memchr (data, '[', 5); + g_assert (start); + len -= (start - (gchar *) data); + + /* ignore anything non-UTF8 for now, in future we might at least allow + * other UTF variants that are clearly prefixed with the appropriate BOM */ + if (!g_utf8_validate (start, len, &end) && (len - (end - start)) > 6) { + GST_FIXME ("non-UTF8 SSA/ASS file"); + return; + } + + /* something at start, but not a UTF-8 BOM? */ + if (data[0] != '[' && (data[0] != 0xEF || data[1] != 0xBB || data[2] != 0xBF)) + return; + + /* ignore any partial UTF-8 characters at the end */ + len = end - start; + + /* create a NUL-terminated string so it's easier to process it safely */ + str = g_strndup (start, len - 1); + script_type = strstr (str, "ScriptType:"); + if (script_type != NULL) { + gdouble version; + + ver_str = script_type + 11; + while (*ver_str == ' ' || *ver_str == 'v' || *ver_str == 'V') + ++ver_str; + version = g_ascii_strtod (ver_str, &p); + if (version == 4.0 && p != NULL && *p == '+') + media_type = "application/x-ass"; + else if (version >= 1.0 && version <= 4.0) + media_type = "application/x-ssa"; + } + + if (media_type == NULL) { + if (strstr (str, "[v4+ Styles]") || strstr (str, "[V4+ Styles]")) + media_type = "application/x-ass"; + else if (strstr (str, "[v4 Styles]") || strstr (str, "[V4 Styles]")) + media_type = "application/x-ssa"; + } + + if (media_type != NULL) { + gst_type_find_suggest_simple (tf, GST_TYPE_FIND_MAXIMUM, + media_type, "parsed", G_TYPE_BOOLEAN, FALSE, NULL); + } else { + GST_WARNING ("could not detect SSA/ASS variant"); + } + + g_free (str); +} + /*** generic typefind for streams that have some data at a specific position***/ typedef struct { @@ -4159,9 +4894,9 @@ G_BEGIN_DECLS{ \ sw_data->data = (const guint8 *)_data; \ sw_data->size = _size; \ sw_data->probability = _probability; \ - sw_data->caps = gst_caps_new_simple (name, NULL); \ + sw_data->caps = gst_caps_new_empty_simple (name); \ if (!gst_type_find_register (plugin, name, rank, start_with_type_find,\ - (char **) ext, sw_data->caps, sw_data, \ + ext, sw_data->caps, sw_data, \ (GDestroyNotify) (sw_data_destroy))) { \ gst_caps_unref (sw_data->caps); \ g_free (sw_data); \ @@ -4189,9 +4924,9 @@ G_BEGIN_DECLS{ \ sw_data->data = (gpointer)_data; \ sw_data->size = 4; \ sw_data->probability = GST_TYPE_FIND_MAXIMUM; \ - sw_data->caps = gst_caps_new_simple (name, NULL); \ + sw_data->caps = gst_caps_new_empty_simple (name); \ if (!gst_type_find_register (plugin, name, rank, riff_type_find, \ - (char **) ext, sw_data->caps, sw_data, \ + ext, sw_data->caps, sw_data, \ (GDestroyNotify) (sw_data_destroy))) { \ gst_caps_unref (sw_data->caps); \ g_free (sw_data); \ @@ -4203,7 +4938,7 @@ G_BEGIN_DECLS{ \ #define TYPE_FIND_REGISTER(plugin,name,rank,func,ext,caps,priv,notify) \ G_BEGIN_DECLS{\ - if (!gst_type_find_register (plugin, name, rank, func, (char **) ext, caps, priv, notify))\ + if (!gst_type_find_register (plugin, name, rank, func, ext, caps, priv, notify))\ return FALSE; \ }G_END_DECLS @@ -4213,302 +4948,195 @@ plugin_init (GstPlugin * plugin) { /* can't initialize this via a struct as caps can't be statically initialized */ - /* note: asx/wax/wmx are XML files, asf doesn't handle them */ - /* FIXME-0.11: these should be const, - this requires gstreamer/gst/gsttypefind::gst_type_find_register() - to have define the parameter as const - */ - static const gchar *asf_exts[] = { "asf", "wm", "wma", "wmv", NULL }; - static const gchar *au_exts[] = { "au", "snd", NULL }; - static const gchar *avi_exts[] = { "avi", NULL }; - static const gchar *qcp_exts[] = { "qcp", NULL }; - static const gchar *cdxa_exts[] = { "dat", NULL }; - static const gchar *flac_exts[] = { "flac", NULL }; - static const gchar *flx_exts[] = { "flc", "fli", NULL }; - static const gchar *id3_exts[] = - { "mp3", "mp2", "mp1", "mpga", "ogg", "flac", "tta", NULL }; - static const gchar *apetag_exts[] = { "mp3", "ape", "mpc", "wv", NULL }; - static const gchar *tta_exts[] = { "tta", NULL }; - static const gchar *mod_exts[] = { "669", "amf", "dsm", "gdm", "far", "imf", - "it", "med", "mod", "mtm", "okt", "sam", - "s3m", "stm", "stx", "ult", "xm", NULL - }; - static const gchar *mp3_exts[] = { "mp3", "mp2", "mp1", "mpga", NULL }; - static const gchar *ac3_exts[] = { "ac3", "eac3", NULL }; - static const gchar *dts_exts[] = { "dts", NULL }; - static const gchar *gsm_exts[] = { "gsm", NULL }; - static const gchar *musepack_exts[] = { "mpc", "mpp", "mp+", NULL }; - static const gchar *mpeg_sys_exts[] = { "mpe", "mpeg", "mpg", NULL }; - static const gchar *mpeg_video_exts[] = { "mpv", "mpeg", "mpg", NULL }; - static const gchar *mpeg_ts_exts[] = { "ts", "mts", NULL }; - static const gchar *ogg_exts[] = { "anx", "ogg", "ogm", NULL }; - static const gchar *qt_exts[] = { "mov", NULL }; - static const gchar *qtif_exts[] = { "qif", "qtif", "qti", NULL }; - static const gchar *mj2_exts[] = { "mj2", NULL }; - static const gchar *jp2_exts[] = { "jp2", NULL }; - static const gchar *rm_exts[] = { "ra", "ram", "rm", "rmvb", NULL }; - static const gchar *swf_exts[] = { "swf", "swfl", NULL }; - static const gchar *utf8_exts[] = { "txt", NULL }; - static const gchar *wav_exts[] = { "wav", NULL }; - static const gchar *aiff_exts[] = { "aiff", "aif", "aifc", NULL }; - static const gchar *svx_exts[] = { "iff", "svx", NULL }; - static const gchar *paris_exts[] = { "paf", NULL }; - static const gchar *nist_exts[] = { "nist", NULL }; - static const gchar *voc_exts[] = { "voc", NULL }; - static const gchar *sds_exts[] = { "sds", NULL }; - static const gchar *ircam_exts[] = { "sf", NULL }; - static const gchar *w64_exts[] = { "w64", NULL }; - static const gchar *shn_exts[] = { "shn", NULL }; - static const gchar *ape_exts[] = { "ape", NULL }; - static const gchar *uri_exts[] = { "ram", NULL }; - static const gchar *hls_exts[] = { "m3u8", NULL }; - static const gchar *sdp_exts[] = { "sdp", NULL }; - static const gchar *smil_exts[] = { "smil", NULL }; - static const gchar *html_exts[] = { "htm", "html", NULL }; - static const gchar *xml_exts[] = { "xml", NULL }; - static const gchar *jpeg_exts[] = { "jpg", "jpe", "jpeg", NULL }; - static const gchar *gif_exts[] = { "gif", NULL }; - static const gchar *png_exts[] = { "png", NULL }; - static const gchar *bmp_exts[] = { "bmp", NULL }; - static const gchar *tiff_exts[] = { "tif", "tiff", NULL }; - static const gchar *matroska_exts[] = { "mkv", "mka", NULL }; - static const gchar *webm_exts[] = { "webm", NULL }; - static const gchar *mve_exts[] = { "mve", NULL }; - static const gchar *dv_exts[] = { "dv", "dif", NULL }; - static const gchar *amr_exts[] = { "amr", NULL }; - static const gchar *ilbc_exts[] = { "ilbc", NULL }; - static const gchar *sid_exts[] = { "sid", NULL }; - static const gchar *xcf_exts[] = { "xcf", NULL }; - static const gchar *mng_exts[] = { "mng", NULL }; - static const gchar *jng_exts[] = { "jng", NULL }; - static const gchar *xpm_exts[] = { "xpm", NULL }; - static const gchar *pnm_exts[] = { "pnm", "ppm", "pgm", "pbm", NULL }; - static const gchar *ras_exts[] = { "ras", NULL }; - static const gchar *bz2_exts[] = { "bz2", NULL }; - static const gchar *gz_exts[] = { "gz", NULL }; - static const gchar *zip_exts[] = { "zip", NULL }; - static const gchar *compress_exts[] = { "Z", NULL }; - static const gchar *m4a_exts[] = { "m4a", NULL }; - static const gchar *q3gp_exts[] = { "3gp", NULL }; - static const gchar *aac_exts[] = { "aac", "adts", "adif", "loas", NULL }; - static const gchar *spc_exts[] = { "spc", NULL }; - static const gchar *wavpack_exts[] = { "wv", "wvp", NULL }; - static const gchar *wavpack_correction_exts[] = { "wvc", NULL }; - static const gchar *rar_exts[] = { "rar", NULL }; - static const gchar *tar_exts[] = { "tar", NULL }; - static const gchar *ar_exts[] = { "a", NULL }; - static const gchar *msdos_exts[] = { "dll", "exe", "ocx", "sys", "scr", - "msstyles", "cpl", NULL - }; - static const gchar *flv_exts[] = { "flv", NULL }; - static const gchar *m4v_exts[] = { "m4v", NULL }; - static const gchar *h263_exts[] = { "h263", "263", NULL }; - static const gchar *h264_exts[] = { "h264", "x264", "264", NULL }; - static const gchar *nuv_exts[] = { "nuv", NULL }; - static const gchar *vivo_exts[] = { "viv", NULL }; - static const gchar *nsf_exts[] = { "nsf", NULL }; - static const gchar *gym_exts[] = { "gym", NULL }; - static const gchar *ay_exts[] = { "ay", NULL }; - static const gchar *gbs_exts[] = { "gbs", NULL }; - static const gchar *kss_exts[] = { "kss", NULL }; - static const gchar *sap_exts[] = { "sap", NULL }; - static const gchar *vgm_exts[] = { "vgm", NULL }; - static const gchar *mid_exts[] = { "mid", "midi", NULL }; - static const gchar *mxmf_exts[] = { "mxmf", NULL }; - static const gchar *imelody_exts[] = { "imy", "ime", "imelody", NULL }; - static const gchar *pdf_exts[] = { "pdf", NULL }; - static const gchar *ps_exts[] = { "ps", NULL }; - static const gchar *svg_exts[] = { "svg", NULL }; - static const gchar *mxf_exts[] = { "mxf", NULL }; - static const gchar *ivf_exts[] = { "ivf", NULL }; - static const gchar *msword_exts[] = { "doc", NULL }; - static const gchar *dsstore_exts[] = { "DS_Store", NULL }; - static const gchar *psd_exts[] = { "psd", NULL }; - static const gchar *y4m_exts[] = { "y4m", NULL }; - GST_DEBUG_CATEGORY_INIT (type_find_debug, "typefindfunctions", GST_DEBUG_FG_GREEN | GST_DEBUG_BG_RED, "generic type find functions"); + /* note: asx/wax/wmx are XML files, asf doesn't handle them */ /* must use strings, macros don't accept initializers */ TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-ms-asf", GST_RANK_SECONDARY, - asf_exts, + "asf,wm,wma,wmv", "\060\046\262\165\216\146\317\021\246\331\000\252\000\142\316\154", 16, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "audio/x-musepack", GST_RANK_PRIMARY, - musepack_type_find, musepack_exts, MUSEPACK_CAPS, NULL, NULL); + musepack_type_find, "mpc,mpp,mp+", MUSEPACK_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-au", GST_RANK_MARGINAL, - au_type_find, au_exts, AU_CAPS, NULL, NULL); + au_type_find, "au,snd", AU_CAPS, NULL, NULL); TYPE_FIND_REGISTER_RIFF (plugin, "video/x-msvideo", GST_RANK_PRIMARY, - avi_exts, "AVI "); + "avi", "AVI "); TYPE_FIND_REGISTER_RIFF (plugin, "audio/qcelp", GST_RANK_PRIMARY, - qcp_exts, "QLCM"); + "qcp", "QLCM"); TYPE_FIND_REGISTER_RIFF (plugin, "video/x-cdxa", GST_RANK_PRIMARY, - cdxa_exts, "CDXA"); + "dat", "CDXA"); TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-vcd", GST_RANK_PRIMARY, - cdxa_exts, "\000\377\377\377\377\377\377\377\377\377\377\000", 12, + "dat", "\000\377\377\377\377\377\377\377\377\377\377\000", 12, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-imelody", GST_RANK_PRIMARY, - imelody_exts, "BEGIN:IMELODY", 13, GST_TYPE_FIND_MAXIMUM); + "imy,ime,imelody", "BEGIN:IMELODY", 13, GST_TYPE_FIND_MAXIMUM); #if 0 TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-smoke", GST_RANK_PRIMARY, NULL, "\x80smoke\x00\x01\x00", 6, GST_TYPE_FIND_MAXIMUM); #endif TYPE_FIND_REGISTER (plugin, "audio/midi", GST_RANK_PRIMARY, mid_type_find, - mid_exts, MID_CAPS, NULL, NULL); + "mid,midi", MID_CAPS, NULL, NULL); TYPE_FIND_REGISTER_RIFF (plugin, "audio/riff-midi", GST_RANK_PRIMARY, - mid_exts, "RMID"); + "mid,midi", "RMID"); TYPE_FIND_REGISTER (plugin, "audio/mobile-xmf", GST_RANK_PRIMARY, - mxmf_type_find, mxmf_exts, MXMF_CAPS, NULL, NULL); + mxmf_type_find, "mxmf", MXMF_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/x-fli", GST_RANK_MARGINAL, flx_type_find, - flx_exts, FLX_CAPS, NULL, NULL); + "flc,fli", FLX_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-id3v2", GST_RANK_PRIMARY + 103, - id3v2_type_find, id3_exts, ID3_CAPS, NULL, NULL); + id3v2_type_find, "mp3,mp2,mp1,mpga,ogg,flac,tta", ID3_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-id3v1", GST_RANK_PRIMARY + 101, - id3v1_type_find, id3_exts, ID3_CAPS, NULL, NULL); + id3v1_type_find, "mp3,mp2,mp1,mpga,ogg,flac,tta", ID3_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-apetag", GST_RANK_PRIMARY + 102, - apetag_type_find, apetag_exts, APETAG_CAPS, NULL, NULL); + apetag_type_find, "mp3,ape,mpc,wv", APETAG_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-ttafile", GST_RANK_PRIMARY, - tta_type_find, tta_exts, TTA_CAPS, NULL, NULL); + tta_type_find, "tta", TTA_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-mod", GST_RANK_SECONDARY, mod_type_find, - mod_exts, MOD_CAPS, NULL, NULL); + "669,amf,dsm,gdm,far,imf,it,med,mod,mtm,okt,sam,s3m,stm,stx,ult,xm", + MOD_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/mpeg", GST_RANK_PRIMARY, mp3_type_find, - mp3_exts, MP3_CAPS, NULL, NULL); + "mp3,mp2,mp1,mpga", MP3_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-ac3", GST_RANK_PRIMARY, ac3_type_find, - ac3_exts, AC3_CAPS, NULL, NULL); + "ac3,eac3", AC3_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-dts", GST_RANK_SECONDARY, dts_type_find, - dts_exts, DTS_CAPS, NULL, NULL); - TYPE_FIND_REGISTER (plugin, "audio/x-gsm", GST_RANK_PRIMARY, NULL, gsm_exts, + "dts", DTS_CAPS, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "audio/x-gsm", GST_RANK_PRIMARY, NULL, "gsm", GSM_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/mpeg-sys", GST_RANK_PRIMARY, - mpeg_sys_type_find, mpeg_sys_exts, MPEG_SYS_CAPS, NULL, NULL); + mpeg_sys_type_find, "mpe,mpeg,mpg", MPEG_SYS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/mpegts", GST_RANK_PRIMARY, - mpeg_ts_type_find, mpeg_ts_exts, MPEGTS_CAPS, NULL, NULL); + mpeg_ts_type_find, "ts,mts", MPEGTS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/ogg", GST_RANK_PRIMARY, - ogganx_type_find, ogg_exts, OGGANX_CAPS, NULL, NULL); + ogganx_type_find, "ogg,oga,ogv,ogm,ogx,spx,anx,axa,axv", OGG_CAPS, + NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/mpeg-elementary", GST_RANK_MARGINAL, - mpeg_video_stream_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL, - NULL); + mpeg_video_stream_type_find, "mpv,mpeg,mpg", MPEG_VIDEO_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/mpeg4", GST_RANK_PRIMARY, - mpeg4_video_type_find, m4v_exts, MPEG_VIDEO_CAPS, NULL, NULL); + mpeg4_video_type_find, "m4v", MPEG_VIDEO_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/x-h263", GST_RANK_SECONDARY, - h263_video_type_find, h263_exts, H263_VIDEO_CAPS, NULL, NULL); + h263_video_type_find, "h263,263", H263_VIDEO_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/x-h264", GST_RANK_PRIMARY, - h264_video_type_find, h264_exts, H264_VIDEO_CAPS, NULL, NULL); + h264_video_type_find, "h264,x264,264", H264_VIDEO_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/x-nuv", GST_RANK_SECONDARY, nuv_type_find, - nuv_exts, NUV_CAPS, NULL, NULL); + "nuv", NUV_CAPS, NULL, NULL); /* ISO formats */ TYPE_FIND_REGISTER (plugin, "audio/x-m4a", GST_RANK_PRIMARY, m4a_type_find, - m4a_exts, M4A_CAPS, NULL, NULL); + "m4a", M4A_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-3gp", GST_RANK_PRIMARY, - q3gp_type_find, q3gp_exts, Q3GP_CAPS, NULL, NULL); + q3gp_type_find, "3gp", Q3GP_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/quicktime", GST_RANK_SECONDARY, - qt_type_find, qt_exts, QT_CAPS, NULL, NULL); + qt_type_find, "mov", QT_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "image/x-quicktime", GST_RANK_SECONDARY, - qtif_type_find, qtif_exts, QTIF_CAPS, NULL, NULL); + qtif_type_find, "qif,qtif,qti", QTIF_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "image/jp2", GST_RANK_PRIMARY, - jp2_type_find, jp2_exts, JP2_CAPS, NULL, NULL); + jp2_type_find, "jp2", JP2_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/mj2", GST_RANK_PRIMARY, - jp2_type_find, mj2_exts, MJ2_CAPS, NULL, NULL); + jp2_type_find, "mj2", MJ2_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "text/html", GST_RANK_SECONDARY, html_type_find, - html_exts, HTML_CAPS, NULL, NULL); + "htm,html", HTML_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "application/vnd.rn-realmedia", - GST_RANK_SECONDARY, rm_exts, ".RMF", 4, GST_TYPE_FIND_MAXIMUM); + GST_RANK_SECONDARY, "ra,ram,rm,rmvb", ".RMF", 4, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-pn-realaudio", - GST_RANK_SECONDARY, rm_exts, ".ra\375", 4, GST_TYPE_FIND_MAXIMUM); + GST_RANK_SECONDARY, "ra,ram,rm,rmvb", ".ra\375", 4, + GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "application/x-shockwave-flash", - GST_RANK_SECONDARY, swf_type_find, swf_exts, SWF_CAPS, NULL, NULL); + GST_RANK_SECONDARY, swf_type_find, "swf,swfl", SWF_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-flv", GST_RANK_SECONDARY, - flv_exts, "FLV", 3, GST_TYPE_FIND_MAXIMUM); + "flv", "FLV", 3, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "text/plain", GST_RANK_MARGINAL, utf8_type_find, - utf8_exts, UTF8_CAPS, NULL, NULL); + "txt", UTF8_CAPS, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "text/utf-16", GST_RANK_MARGINAL, utf16_type_find, + "txt", UTF16_CAPS, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "text/utf-32", GST_RANK_MARGINAL, utf32_type_find, + "txt", UTF32_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "text/uri-list", GST_RANK_MARGINAL, uri_type_find, - uri_exts, URI_CAPS, NULL, NULL); + "ram", URI_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-hls", GST_RANK_MARGINAL, - hls_type_find, hls_exts, HLS_CAPS, NULL, NULL); + hls_type_find, "m3u8", HLS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/sdp", GST_RANK_SECONDARY, - sdp_type_find, sdp_exts, SDP_CAPS, NULL, NULL); + sdp_type_find, "sdp", SDP_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/smil", GST_RANK_SECONDARY, - smil_type_find, smil_exts, SMIL_CAPS, NULL, NULL); + smil_type_find, "smil", SMIL_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/xml", GST_RANK_MARGINAL, - xml_type_find, xml_exts, GENERIC_XML_CAPS, NULL, NULL); - TYPE_FIND_REGISTER_RIFF (plugin, "audio/x-wav", GST_RANK_PRIMARY, wav_exts, + xml_type_find, "xml", GENERIC_XML_CAPS, NULL, NULL); + TYPE_FIND_REGISTER_RIFF (plugin, "audio/x-wav", GST_RANK_PRIMARY, "wav", "WAVE"); TYPE_FIND_REGISTER (plugin, "audio/x-aiff", GST_RANK_SECONDARY, - aiff_type_find, aiff_exts, AIFF_CAPS, NULL, NULL); + aiff_type_find, "aiff,aif,aifc", AIFF_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-svx", GST_RANK_SECONDARY, svx_type_find, - svx_exts, SVX_CAPS, NULL, NULL); + "iff,svx", SVX_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-paris", GST_RANK_SECONDARY, - paris_type_find, paris_exts, PARIS_CAPS, NULL, NULL); + paris_type_find, "paf", PARIS_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-nist", GST_RANK_SECONDARY, - nist_exts, "NIST", 4, GST_TYPE_FIND_MAXIMUM); + "nist", "NIST", 4, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-voc", GST_RANK_SECONDARY, - voc_exts, "Creative", 8, GST_TYPE_FIND_MAXIMUM); + "voc", "Creative", 8, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "audio/x-sds", GST_RANK_SECONDARY, sds_type_find, - sds_exts, SDS_CAPS, NULL, NULL); + "sds", SDS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-ircam", GST_RANK_SECONDARY, - ircam_type_find, ircam_exts, IRCAM_CAPS, NULL, NULL); + ircam_type_find, "sf", IRCAM_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-w64", GST_RANK_SECONDARY, - w64_exts, "riff", 4, GST_TYPE_FIND_MAXIMUM); + "w64", "riff", 4, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "audio/x-shorten", GST_RANK_SECONDARY, - shn_type_find, shn_exts, SHN_CAPS, NULL, NULL); + shn_type_find, "shn", SHN_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-ape", GST_RANK_SECONDARY, - ape_type_find, ape_exts, APE_CAPS, NULL, NULL); + ape_type_find, "ape", APE_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "image/jpeg", GST_RANK_PRIMARY + 15, - jpeg_type_find, jpeg_exts, JPEG_CAPS, NULL, NULL); - TYPE_FIND_REGISTER_START_WITH (plugin, "image/gif", GST_RANK_PRIMARY, - gif_exts, "GIF8", 4, GST_TYPE_FIND_MAXIMUM); + jpeg_type_find, "jpg,jpe,jpeg", JPEG_CAPS, NULL, NULL); + TYPE_FIND_REGISTER_START_WITH (plugin, "image/gif", GST_RANK_PRIMARY, "gif", + "GIF8", 4, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "image/png", GST_RANK_PRIMARY + 14, - png_exts, "\211PNG\015\012\032\012", 8, GST_TYPE_FIND_MAXIMUM); + "png", "\211PNG\015\012\032\012", 8, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "image/bmp", GST_RANK_PRIMARY, bmp_type_find, - bmp_exts, BMP_CAPS, NULL, NULL); + "bmp", BMP_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "image/tiff", GST_RANK_PRIMARY, tiff_type_find, - tiff_exts, TIFF_CAPS, NULL, NULL); + "tif,tiff", TIFF_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "image/x-portable-pixmap", GST_RANK_SECONDARY, - pnm_type_find, pnm_exts, PNM_CAPS, NULL, NULL); + pnm_type_find, "pnm,ppm,pgm,pbm", PNM_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/x-matroska", GST_RANK_PRIMARY, - matroska_type_find, matroska_exts, MATROSKA_CAPS, NULL, NULL); - TYPE_FIND_REGISTER (plugin, "video/webm", GST_RANK_PRIMARY, - webm_type_find, webm_exts, WEBM_CAPS, NULL, NULL); + matroska_type_find, "mkv,mka,mk3d,webm", MATROSKA_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/mxf", GST_RANK_PRIMARY, - mxf_type_find, mxf_exts, MXF_CAPS, NULL, NULL); + mxf_type_find, "mxf", MXF_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-mve", GST_RANK_SECONDARY, - mve_exts, "Interplay MVE File\032\000\032\000\000\001\063\021", 26, + "mve", "Interplay MVE File\032\000\032\000\000\001\063\021", 26, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "video/x-dv", GST_RANK_SECONDARY, dv_type_find, - dv_exts, DV_CAPS, NULL, NULL); + "dv,dif", DV_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-amr-nb-sh", GST_RANK_PRIMARY, - amr_exts, "#!AMR", 5, GST_TYPE_FIND_LIKELY); + "amr", "#!AMR", 5, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-amr-wb-sh", GST_RANK_PRIMARY, - amr_exts, "#!AMR-WB", 7, GST_TYPE_FIND_MAXIMUM); - TYPE_FIND_REGISTER (plugin, "audio/iLBC-sh", GST_RANK_PRIMARY, - ilbc_type_find, ilbc_exts, ILBC_CAPS, NULL, NULL); + "amr", "#!AMR-WB", 7, GST_TYPE_FIND_MAXIMUM); + TYPE_FIND_REGISTER (plugin, "audio/iLBC-sh", GST_RANK_PRIMARY, ilbc_type_find, + "ilbc", ILBC_CAPS, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "audio/x-sbc", GST_RANK_MARGINAL, sbc_type_find, + "sbc", SBC_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-sid", GST_RANK_MARGINAL, - sid_exts, "PSID", 4, GST_TYPE_FIND_MAXIMUM); + "sid", "PSID", 4, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "image/x-xcf", GST_RANK_SECONDARY, - xcf_exts, "gimp xcf", 8, GST_TYPE_FIND_MAXIMUM); + "xcf", "gimp xcf", 8, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-mng", GST_RANK_SECONDARY, - mng_exts, "\212MNG\015\012\032\012", 8, GST_TYPE_FIND_MAXIMUM); + "mng", "\212MNG\015\012\032\012", 8, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "image/x-jng", GST_RANK_SECONDARY, - jng_exts, "\213JNG\015\012\032\012", 8, GST_TYPE_FIND_MAXIMUM); + "jng", "\213JNG\015\012\032\012", 8, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "image/x-xpixmap", GST_RANK_SECONDARY, - xpm_exts, "/* XPM */", 9, GST_TYPE_FIND_MAXIMUM); + "xpm", "/* XPM */", 9, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "image/x-sun-raster", - GST_RANK_SECONDARY, ras_exts, "\131\246\152\225", 4, - GST_TYPE_FIND_MAXIMUM); + GST_RANK_SECONDARY, "ras", "\131\246\152\225", 4, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-bzip", - GST_RANK_SECONDARY, bz2_exts, "BZh", 3, GST_TYPE_FIND_LIKELY); + GST_RANK_SECONDARY, "bz2", "BZh", 3, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-gzip", - GST_RANK_SECONDARY, gz_exts, "\037\213", 2, GST_TYPE_FIND_LIKELY); + GST_RANK_SECONDARY, "gz", "\037\213", 2, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER_START_WITH (plugin, "application/zip", GST_RANK_SECONDARY, - zip_exts, "PK\003\004", 4, GST_TYPE_FIND_LIKELY); + "zip", "PK\003\004", 4, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-compress", - GST_RANK_SECONDARY, compress_exts, "\037\235", 2, GST_TYPE_FIND_LIKELY); + GST_RANK_SECONDARY, "Z", "\037\235", 2, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER (plugin, "subtitle/x-kate", GST_RANK_MARGINAL, kate_type_find, NULL, NULL, NULL, NULL); - TYPE_FIND_REGISTER (plugin, "audio/x-flac", GST_RANK_PRIMARY, - flac_type_find, flac_exts, FLAC_CAPS, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "audio/x-flac", GST_RANK_PRIMARY, flac_type_find, + "flac", FLAC_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-vorbis", GST_RANK_PRIMARY, vorbis_type_find, NULL, VORBIS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/x-theora", GST_RANK_PRIMARY, @@ -4521,76 +5149,75 @@ plugin_init (GstPlugin * plugin) ogmtext_type_find, NULL, OGMTEXT_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-speex", GST_RANK_PRIMARY, speex_type_find, NULL, SPEEX_CAPS, NULL, NULL); - TYPE_FIND_REGISTER (plugin, "audio/x-celt", GST_RANK_PRIMARY, - celt_type_find, NULL, CELT_CAPS, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "audio/x-celt", GST_RANK_PRIMARY, celt_type_find, + NULL, CELT_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-ogg-skeleton", GST_RANK_PRIMARY, oggskel_type_find, NULL, OGG_SKELETON_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "text/x-cmml", GST_RANK_PRIMARY, cmml_type_find, NULL, CMML_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-executable", GST_RANK_MARGINAL, NULL, "\177ELF", 4, GST_TYPE_FIND_MAXIMUM); - TYPE_FIND_REGISTER (plugin, "audio/aac", GST_RANK_SECONDARY, - aac_type_find, aac_exts, AAC_CAPS, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "audio/aac", GST_RANK_SECONDARY, aac_type_find, + "aac,adts,adif,loas", AAC_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-spc", GST_RANK_SECONDARY, - spc_exts, "SNES-SPC700 Sound File Data", 27, GST_TYPE_FIND_MAXIMUM); + "spc", "SNES-SPC700 Sound File Data", 27, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "audio/x-wavpack", GST_RANK_SECONDARY, - wavpack_type_find, wavpack_exts, WAVPACK_CAPS, NULL, NULL); + wavpack_type_find, "wv,wvp", WAVPACK_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-wavpack-correction", GST_RANK_SECONDARY, - wavpack_type_find, wavpack_correction_exts, WAVPACK_CORRECTION_CAPS, NULL, - NULL); + wavpack_type_find, "wvc", WAVPACK_CORRECTION_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/postscript", GST_RANK_SECONDARY, - postscript_type_find, ps_exts, POSTSCRIPT_CAPS, NULL, NULL); + postscript_type_find, "ps", POSTSCRIPT_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "image/svg+xml", GST_RANK_SECONDARY, - svg_type_find, svg_exts, SVG_CAPS, NULL, NULL); + svg_type_find, "svg", SVG_CAPS, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-rar", - GST_RANK_SECONDARY, rar_exts, "Rar!", 4, GST_TYPE_FIND_LIKELY); + GST_RANK_SECONDARY, "rar", "Rar!", 4, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER (plugin, "application/x-tar", GST_RANK_SECONDARY, - tar_type_find, tar_exts, TAR_CAPS, NULL, NULL); + tar_type_find, "tar", TAR_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-ar", GST_RANK_SECONDARY, - ar_type_find, ar_exts, AR_CAPS, NULL, NULL); + ar_type_find, "a", AR_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-ms-dos-executable", - GST_RANK_SECONDARY, msdos_type_find, msdos_exts, MSDOS_CAPS, NULL, NULL); + GST_RANK_SECONDARY, msdos_type_find, "dll,exe,ocx,sys,scr,msstyles,cpl", + MSDOS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/x-dirac", GST_RANK_PRIMARY, dirac_type_find, NULL, DIRAC_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "multipart/x-mixed-replace", GST_RANK_SECONDARY, multipart_type_find, NULL, MULTIPART_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/x-mmsh", GST_RANK_SECONDARY, mmsh_type_find, NULL, MMSH_CAPS, NULL, NULL); - TYPE_FIND_REGISTER (plugin, "video/vivo", GST_RANK_SECONDARY, - vivo_type_find, vivo_exts, VIVO_CAPS, NULL, NULL); - TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-nsf", - GST_RANK_SECONDARY, nsf_exts, "NESM\x1a", 5, GST_TYPE_FIND_MAXIMUM); - TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-gym", - GST_RANK_SECONDARY, gym_exts, "GYMX", 4, GST_TYPE_FIND_MAXIMUM); - TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-ay", - GST_RANK_SECONDARY, ay_exts, "ZXAYEMUL", 8, GST_TYPE_FIND_MAXIMUM); - TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-gbs", - GST_RANK_SECONDARY, gbs_exts, "GBS\x01", 4, GST_TYPE_FIND_MAXIMUM); - TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-vgm", - GST_RANK_SECONDARY, vgm_exts, "Vgm\x20", 4, GST_TYPE_FIND_MAXIMUM); - TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-sap", - GST_RANK_SECONDARY, sap_exts, "SAP\x0d\x0a" "AUTHOR\x20", 12, - GST_TYPE_FIND_MAXIMUM); + TYPE_FIND_REGISTER (plugin, "video/vivo", GST_RANK_SECONDARY, vivo_type_find, + "viv", VIVO_CAPS, NULL, NULL); + TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-nsf", GST_RANK_SECONDARY, + "nsf", "NESM\x1a", 5, GST_TYPE_FIND_MAXIMUM); + TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-gym", GST_RANK_SECONDARY, + "gym", "GYMX", 4, GST_TYPE_FIND_MAXIMUM); + TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-ay", GST_RANK_SECONDARY, "ay", + "ZXAYEMUL", 8, GST_TYPE_FIND_MAXIMUM); + TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-gbs", GST_RANK_SECONDARY, + "gbs", "GBS\x01", 4, GST_TYPE_FIND_MAXIMUM); + TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-vgm", GST_RANK_SECONDARY, + "vgm", "Vgm\x20", 4, GST_TYPE_FIND_MAXIMUM); + TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-sap", GST_RANK_SECONDARY, + "sap", "SAP\x0d\x0a" "AUTHOR\x20", 12, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "video/x-ivf", GST_RANK_SECONDARY, - ivf_exts, "DKIF", 4, GST_TYPE_FIND_NEARLY_CERTAIN); + "ivf", "DKIF", 4, GST_TYPE_FIND_NEARLY_CERTAIN); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-kss", GST_RANK_SECONDARY, - kss_exts, "KSSX\0", 5, GST_TYPE_FIND_MAXIMUM); + "kss", "KSSX\0", 5, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "application/pdf", GST_RANK_SECONDARY, - pdf_exts, "%PDF-", 5, GST_TYPE_FIND_LIKELY); + "pdf", "%PDF-", 5, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER_START_WITH (plugin, "application/msword", - GST_RANK_SECONDARY, msword_exts, "\320\317\021\340\241\261\032\341", 8, + GST_RANK_SECONDARY, "doc", "\320\317\021\340\241\261\032\341", 8, GST_TYPE_FIND_LIKELY); /* Mac OS X .DS_Store files tend to be taken for video/mpeg */ TYPE_FIND_REGISTER_START_WITH (plugin, "application/octet-stream", - GST_RANK_SECONDARY, dsstore_exts, "\000\000\000\001Bud1", 8, + GST_RANK_SECONDARY, "DS_Store", "\000\000\000\001Bud1", 8, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER_START_WITH (plugin, "image/vnd.adobe.photoshop", - GST_RANK_SECONDARY, psd_exts, "8BPS\000\001\000\000\000\000", 10, + GST_RANK_SECONDARY, "psd", "8BPS\000\001\000\000\000\000", 10, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER (plugin, "image/vnd.wap.wbmp", GST_RANK_MARGINAL, wbmp_typefind, NULL, NULL, NULL, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-yuv4mpeg", - GST_RANK_SECONDARY, y4m_exts, "YUV4MPEG2 ", 10, GST_TYPE_FIND_LIKELY); + GST_RANK_SECONDARY, "y4m", "YUV4MPEG2 ", 10, GST_TYPE_FIND_LIKELY); TYPE_FIND_REGISTER (plugin, "image/x-icon", GST_RANK_MARGINAL, windows_icon_typefind, NULL, NULL, NULL, NULL); @@ -4601,12 +5228,17 @@ plugin_init (GstPlugin * plugin) TYPE_FIND_REGISTER (plugin, "image/x-degas", GST_RANK_MARGINAL, degas_type_find, NULL, NULL, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "application/octet-stream", GST_RANK_MARGINAL, + dvdiso_type_find, NULL, NULL, NULL, NULL); + + TYPE_FIND_REGISTER (plugin, "application/x-ssa", GST_RANK_SECONDARY, + ssa_type_find, "ssa,ass", NULL, NULL, NULL); return TRUE; } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - "typefindfunctions", + typefindfunctions, "default typefind functions", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)