mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
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.
This commit is contained in:
parent
0947ecf74c
commit
f8977b9e9e
2 changed files with 99 additions and 73 deletions
25
ChangeLog
25
ChangeLog
|
@ -1,3 +1,22 @@
|
|||
2008-04-30 Tim-Philipp Müller <tim.muller at collabora co uk>
|
||||
|
||||
* 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 <msmith@songbirdnest.com>
|
||||
|
||||
* 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 <msmith@songbirdnest.com>
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue