From 497d87061d3c932e262c97b1882b1ebbb1113aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 15 Apr 2012 22:32:06 +0100 Subject: [PATCH] typefinding: more fine-grained ogg typefinding Typefind to audio/ogg, video/ogg, etc. Also change application/x-annodex to application/annodex. See http://wiki.xiph.org/MIME_Types_and_File_Extensions --- gst/typefind/gsttypefindfunctions.c | 123 ++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 14 deletions(-) diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c index 50beb0ae1e..d6d787aace 100644 --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -3589,30 +3589,124 @@ 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"); +/*** Ogg and Annodex variants ***/ static GstStaticCaps ogg_annodex_caps = - GST_STATIC_CAPS ("application/ogg;application/x-annodex"); + GST_STATIC_CAPS ("application/ogg;video/ogg;audio/ogg;" + "application/annodex;audio/annodex;video/annodex;application/kate"); #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} + }; - if ((data != NULL) && (memcmp (data, "OggS", 4) == 0)) { + while (c.offset < 4096 && data_scan_ctx_ensure_data (tf, &c, 64)) { + guint size, i; - /* 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)); + if (memcmp (c.data, "OggS", 5) != 0) + break; - gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, - gst_static_caps_get (&ogg_caps)); + ++ogg_syncs; + + /* check if BOS */ + if (c.data[5] != 0x02) + break; + + /* 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; + + /* FIXME: what about XSPF? */ + if (hdr_count[OGG_ANNODEX] > 0) { + if (hdr_count[OGG_VIDEO] > 0) + media_type = "video/annodex"; + else if (hdr_count[OGG_AUDIO] > 0) + media_type = "audio/annodex"; + else + media_type = "application/annodex"; + } else 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 ***/ @@ -4455,7 +4549,8 @@ plugin_init (GstPlugin * plugin) TYPE_FIND_REGISTER (plugin, "video/mpegts", GST_RANK_PRIMARY, mpeg_ts_type_find, "ts,mts", MPEGTS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/ogg", GST_RANK_PRIMARY, - ogganx_type_find, "anx,ogg,ogm", OGGANX_CAPS, NULL, NULL); + ogganx_type_find, "ogg,oga,ogv,ogm,ogx,spx,anx,axa,axv", OGGANX_CAPS, + NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/mpeg-elementary", GST_RANK_MARGINAL, mpeg_video_stream_type_find, "mpv,mpeg,mpg", MPEG_VIDEO_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/mpeg4", GST_RANK_PRIMARY,