From 54329ade6a5032cf04975229b835cf0973dd1585 Mon Sep 17 00:00:00 2001 From: Gwenole Beauchesne Date: Thu, 24 Jan 2013 11:21:28 +0100 Subject: [PATCH] typefind: detect VC-1 elementary streams. Signed-off-by: Gwenole Beauchesne --- gst/typefind/gsttypefindfunctions.c | 120 +++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c index 19ee389..0a2de49 100644 --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -2470,6 +2470,123 @@ h264_video_type_find (GstTypeFind * tf, gpointer unused) } } +/*** video/x-wmv VC-1 elementary video stream ***/ + +static GstStaticCaps vc1_video_caps = +GST_STATIC_CAPS ("video/x-wmv,wmvversion=3,stream-format=bdu"); + +#define VC1_VIDEO_CAPS gst_static_caps_get(&vc1_video_caps) + +#define VC1_MAX_PROBE_LENGTH (128 * 1024) + +static void +vc1_video_type_find (GstTypeFind * tf, gpointer unused) +{ + DataScanCtx c = { 0, NULL, 0 }; + + /* BDUs consist of the Start Code Prefix (SCP = 00 00 01) followed + * by the Start Code Suffix (SCS), which represents the BDU type */ + guint8 scs; + guint8 profile = 0; + guint eos_hdrs = 0; + guint seq_hdrs = 0; + guint pic_hdrs = 0; + guint etp_hdrs = 0; + guint bad = 0; + + while (c.offset < VC1_MAX_PROBE_LENGTH) { + if (G_UNLIKELY (!data_scan_ctx_ensure_data (tf, &c, 4))) + break; + + if (!IS_MPEG_HEADER (c.data)) { + data_scan_ctx_advance (tf, &c, 1); + continue; + } + + /* Collect statistics about the BDU types */ + scs = c.data[3]; + switch (scs) { + case 0x0a: + /* End-of-Sequence */ + eos_hdrs++; + break; + case 0x0f: + /* Sequence Header */ + seq_hdrs++; + if (G_UNLIKELY (!data_scan_ctx_ensure_data (tf, &c, 5))) + break; + profile = (c.data[4] >> 6) & 3; + if (profile != 3) + bad++; + if (((c.data[4] >> 3) & 7) > 4) /* level */ + bad++; + if (((c.data[4] >> 1) & 3) != 1) /* color difference format */ + bad++; + break; + case 0x0b: + /* Slice */ + case 0x0c: + /* Field */ + case 0x0d: + /* Frame */ + pic_hdrs++; + break; + case 0x0e: + /* Entry-point header */ + etp_hdrs++; + if (profile != 3) + bad++; + break; + default: + /* User data */ + if (scs >= 0x1b && scs <= 0x1f) + break; + + /* Forbidden */ + if (scs >= 0x80 && scs <= 0xff) + bad++; + + /* SMPTE Reserved */ + else + bad++; + break; + } + + if (seq_hdrs + etp_hdrs + pic_hdrs >= 10 && bad < 4) + break; + + data_scan_ctx_advance (tf, &c, 4); + } + + GST_LOG ("bad:%u, seq:%u, pic:%u, etp:%u", bad, seq_hdrs, pic_hdrs, etp_hdrs); + + if (pic_hdrs > 0) { + GstTypeFindProbability probability = 0; + GstCaps *caps; + + if (seq_hdrs > 0 && pic_hdrs >= GST_MPEGVID_TYPEFIND_TRY_PICTURES && + etp_hdrs > 0 && eos_hdrs <= seq_hdrs && bad == 0) + probability = GST_TYPE_FIND_NEARLY_CERTAIN - 9; + else if (pic_hdrs >= GST_MPEGVID_TYPEFIND_TRY_PICTURES && bad == 0) + probability = GST_TYPE_FIND_LIKELY + 5; + else if (pic_hdrs >= 3 && bad == 0) + probability = GST_TYPE_FIND_LIKELY; + else if (pic_hdrs > 0 && bad == 0) + probability = GST_TYPE_FIND_POSSIBLE; + else if (pic_hdrs > 0 && bad < 4) + probability = GST_TYPE_FIND_POSSIBLE - 5; + else + probability = GST_TYPE_FIND_POSSIBLE - 10; + + caps = gst_caps_copy (VC1_VIDEO_CAPS); + if (seq_hdrs > 0 && profile == 3) + gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, + GST_MAKE_FOURCC ('W', 'V', 'C', '1'), NULL); + gst_type_find_suggest (tf, probability, caps); + gst_caps_unref (caps); + } +} + /*** video/mpeg video stream ***/ static GstStaticCaps mpeg_video_caps = GST_STATIC_CAPS ("video/mpeg, " @@ -4540,6 +4657,7 @@ plugin_init (GstPlugin * plugin) static const gchar *dsstore_exts[] = { "DS_Store", NULL }; static const gchar *psd_exts[] = { "psd", NULL }; static const gchar *y4m_exts[] = { "y4m", NULL }; + static const gchar *vc1_exts[] = { "vc1", NULL }; GST_DEBUG_CATEGORY_INIT (type_find_debug, "typefindfunctions", GST_DEBUG_FG_GREEN | GST_DEBUG_BG_RED, "generic type find functions"); @@ -4611,6 +4729,8 @@ plugin_init (GstPlugin * plugin) h264_video_type_find, h264_exts, H264_VIDEO_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/x-nuv", GST_RANK_SECONDARY, nuv_type_find, nuv_exts, NUV_CAPS, NULL, NULL); + TYPE_FIND_REGISTER (plugin, "video/x-wmv", GST_RANK_PRIMARY, + vc1_video_type_find, vc1_exts, VC1_VIDEO_CAPS, NULL, NULL); /* ISO formats */ TYPE_FIND_REGISTER (plugin, "audio/x-m4a", GST_RANK_PRIMARY, m4a_type_find, -- 1.7.9.5