From f8977b9e9ec4be4d896cdd92d5d56b583fddc134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 30 Apr 2008 20:54:56 +0000 Subject: [PATCH] gst/typefind/gsttypefindfunctions.c: Rework mpeg video stream typefinding a bit more: make sure sequence, Original commit message from CVS: * gst/typefind/gsttypefindfunctions.c: (mpeg_video_stream_ctx_ensure_data), (mpeg_video_stream_type_find), (plugin_init): Rework mpeg video stream typefinding a bit more: make sure sequence, GOP, picture and slice headers appear in the order they should and that we've in fact at least had one of each; fix picture header detection; decouple picture and slice header check - don't assume they're at a fixed offset, there may be extra data in between. Also, announce varying degrees of probability depending on what we found exactly (multiple pictures, at least one picture, just sequence and GOP headers). Finally, in _ensure_data(), take into account that we might be typefinding smaller amounts of data, such as the first buffer of a stream, so fall back to the minimum size needed as long as that's available, instead of erroring out if there's less than 2kB of data. Fixes #526173. Conveniently also doesn't recognise the fuzzed file from #399342 as valid. --- ChangeLog | 25 ++++- gst/typefind/gsttypefindfunctions.c | 147 +++++++++++++++------------- 2 files changed, 99 insertions(+), 73 deletions(-) diff --git a/ChangeLog b/ChangeLog index fe1c7f5c03..336e0a928e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2008-04-30 Tim-Philipp Müller + + * gst/typefind/gsttypefindfunctions.c: + (mpeg_video_stream_ctx_ensure_data), (mpeg_video_stream_type_find), + (plugin_init): + Rework mpeg video stream typefinding a bit more: make sure sequence, + GOP, picture and slice headers appear in the order they should and + that we've in fact at least had one of each; fix picture header + detection; decouple picture and slice header check - don't assume + they're at a fixed offset, there may be extra data in between. Also, + announce varying degrees of probability depending on what we found + exactly (multiple pictures, at least one picture, just sequence and + GOP headers). Finally, in _ensure_data(), take into account that we + might be typefinding smaller amounts of data, such as the first + buffer of a stream, so fall back to the minimum size needed as long + as that's available, instead of erroring out if there's less than + 2kB of data. Fixes #526173. Conveniently also doesn't recognise the + fuzzed file from #399342 as valid. + 2008-04-30 Michael Smith * ext/theora/theoradec.c: @@ -10,9 +29,9 @@ * gst/typefind/gsttypefindfunctions.c: (MpegVideoStreamCtx), (mpeg_video_stream_ctx_advance), (mpeg_video_stream_ctx_ensure_data), (mpeg_video_stream_type_find): - Refactor a bit: use context structure to track parsing offset and size of - available data and make the code a bit clearer. Fixes bad memory access - in #356937. + Refactor a bit: use context structure to track parsing offset and + size of available data and make the code a bit clearer. Fixes bad + memory access in #356937. 2008-04-28 Michael Smith diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c index acad8f9ed1..5f8c284339 100644 --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -1636,23 +1636,6 @@ done: static GstStaticCaps mpeg_video_caps = GST_STATIC_CAPS ("video/mpeg, " "systemstream = (boolean) false"); #define MPEG_VIDEO_CAPS gst_static_caps_get(&mpeg_video_caps) -static void -mpeg_video_type_find (GstTypeFind * tf, gpointer unused) -{ - static const guint8 sequence_header[] = { 0x00, 0x00, 0x01, 0xb3 }; - guint8 *data = NULL; - - data = gst_type_find_peek (tf, 0, 8); - - if (data && memcmp (data, sequence_header, 4) == 0) { - GstCaps *caps = gst_caps_copy (MPEG_VIDEO_CAPS); - - gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion", - G_TYPE_INT, 1, NULL); - gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE, caps); - gst_caps_unref (caps); - } -} /* * Idea is the same as MPEG system stream typefinding: We check each @@ -1696,76 +1679,102 @@ mpeg_video_stream_ctx_ensure_data (GstTypeFind * tf, MpegVideoStreamCtx * c, return TRUE; c->data = gst_type_find_peek (tf, c->offset, GST_MPEGVID_TYPEFIND_SYNC_SIZE); - if (c->data == NULL) - return FALSE; + if (c->data != NULL) { + c->size = GST_MPEGVID_TYPEFIND_SYNC_SIZE; + return TRUE; + } - c->size = GST_MPEGVID_TYPEFIND_SYNC_SIZE; - return TRUE; + /* try min_size as fallback: we might be typefinding the first buffer of the + * stream and not have as much data available as we'd like */ + c->data = gst_type_find_peek (tf, c->offset, min_len); + if (c->data != NULL) { + c->size = min_len; + return TRUE; + } + + return FALSE; } static void mpeg_video_stream_type_find (GstTypeFind * tf, gpointer unused) { MpegVideoStreamCtx c = { 0, NULL, 0 }; + gboolean seen_seq = FALSE; + gboolean seen_gop = FALSE; + guint num_pic_headers = 0; gint found = 0; - while (1) { - if (found >= GST_MPEGVID_TYPEFIND_TRY_PICTURES) { - GstCaps *caps = gst_caps_copy (MPEG_VIDEO_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 - 2, caps); - gst_caps_unref (caps); - return; - } - - if (c.offset >= GST_MPEGVID_TYPEFIND_TRY_SYNC) + while (c.offset < GST_MPEGVID_TYPEFIND_TRY_SYNC) { + if (found >= GST_MPEGVID_TYPEFIND_TRY_PICTURES) break; if (!mpeg_video_stream_ctx_ensure_data (tf, &c, 5)) break; - if (IS_MPEG_HEADER (c.data)) { - /* An MPEG PACK header indicates that this isn't an elementary stream */ - if (IS_MPEG_PACK_CODE (c.data[3])) { - if (mpeg_sys_is_valid_pack (tf, c.data, c.size, NULL)) - break; - } + if (!IS_MPEG_HEADER (c.data)) + goto next; - /* are we a sequence (0xB3) header? */ - if (c.data[3] == 0xB3) { - mpeg_video_stream_ctx_advance (tf, &c, 4 + 8); - continue; - } + /* a pack header indicates that this isn't an elementary stream */ + if (c.data[3] == 0xBA && mpeg_sys_is_valid_pack (tf, c.data, c.size, NULL)) + return; - /* ... or a GOP (0xB8) header? */ - if (c.data[3] == 0xB8) { - mpeg_video_stream_ctx_advance (tf, &c, 8); - continue; - } - - /* ... else, we should now see an image header ... */ - /* is [4] really what we want here, not [3]? Won't [4] == 0 only work for - * the first image or the first few images? (tpm) */ - if (c.data[4] == 0x00) { - mpeg_video_stream_ctx_advance (tf, &c, 8); - - if (!mpeg_video_stream_ctx_ensure_data (tf, &c, 5)) - break; - - /* .. followed by a slice header */ - if ((IS_MPEG_HEADER (c.data + 0) && c.data[3] == 0x01) || - (IS_MPEG_HEADER (c.data + 1) && c.data[4] == 0x01)) { - mpeg_video_stream_ctx_advance (tf, &c, 4); - found += 1; - continue; - } - } + /* do we have a sequence header? */ + if (c.data[3] == 0xB3) { + seen_seq = TRUE; + mpeg_video_stream_ctx_advance (tf, &c, 4 + 8); + continue; } + /* we really want to see a sequence header first */ + if (!seen_seq) + goto next; + + /* next, a GOP header would be nice */ + if (c.data[3] == 0xB8) { + seen_gop = TRUE; + mpeg_video_stream_ctx_advance (tf, &c, 8); + continue; + } + + /* we really want to see a sequence+GOP header before continuing */ + if (!seen_gop) + goto next; + + /* now that we've had a sequence+GOP, we'd like to see a picture header */ + if (c.data[3] == 0x00) { + ++num_pic_headers; + mpeg_video_stream_ctx_advance (tf, &c, 8); + continue; + } + + /* ... each followed by a slice header with slice_vertical_pos=1 */ + if (c.data[3] == 0x01 && num_pic_headers > found) { + mpeg_video_stream_ctx_advance (tf, &c, 4); + found += 1; + continue; + } + + next: + mpeg_video_stream_ctx_advance (tf, &c, 1); } + + if (found > 0 || num_pic_headers > 0) { + GstTypeFindProbability probability; + GstCaps *caps; + + if (found >= GST_MPEGVID_TYPEFIND_TRY_PICTURES) + probability = GST_TYPE_FIND_MAXIMUM - 2; + else if (found > 0) + probability = GST_TYPE_FIND_POSSIBLE + 1; + else + probability = GST_TYPE_FIND_POSSIBLE - 10; + + caps = gst_caps_copy (MPEG_VIDEO_CAPS); + gst_caps_set_simple (caps, "mpegversion", G_TYPE_INT, 1, NULL); + gst_type_find_suggest (tf, probability, caps); + gst_caps_unref (caps); + } } /*** audio/x-aiff ***/ @@ -3054,9 +3063,7 @@ plugin_init (GstPlugin * plugin) mpeg_ts_type_find, mpeg_ts_exts, MPEGTS_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "application/ogg", GST_RANK_PRIMARY, ogganx_type_find, ogg_exts, OGGANX_CAPS, NULL, NULL); - TYPE_FIND_REGISTER (plugin, "video/mpeg,elementary", GST_RANK_SECONDARY, - 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-elementary", GST_RANK_MARGINAL, mpeg_video_stream_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL, NULL); TYPE_FIND_REGISTER (plugin, "video/mpeg4", GST_RANK_PRIMARY,