From 830a4aa7f4788f3b5a874ed68a80ceae66473c47 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 11 Nov 2013 16:15:00 +0100 Subject: [PATCH] mpegvideoparse: look beyond start code before leaping In case more data than a start code alone is needed to decide whether it ends a frame, arrange for more input data and decide when available. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711627 --- gst/videoparsers/gstmpegvideoparse.c | 50 ++++++++++++++++++---------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/gst/videoparsers/gstmpegvideoparse.c b/gst/videoparsers/gstmpegvideoparse.c index bff98f8c27..1feb3c52b4 100644 --- a/gst/videoparsers/gstmpegvideoparse.c +++ b/gst/videoparsers/gstmpegvideoparse.c @@ -461,18 +461,21 @@ parse_packet_extension (GstMpegvParse * mpvparse, GstMapInfo * info, guint off) } } -/* caller guarantees at least start code in @buf at @off */ +/* caller guarantees at least start code in @buf at @off ( - 4)*/ /* for off == 4 initial code; returns TRUE if code starts a frame * otherwise returns TRUE if code terminates preceding frame */ static gboolean gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse, - GstMapInfo * info, gint off, GstMpegVideoPacket * packet) + GstMapInfo * info, gint off, GstMpegVideoPacket * packet, + gboolean * need_more) { gboolean ret = FALSE, checkconfig = TRUE; GST_LOG_OBJECT (mpvparse, "process startcode %x (%s) offset:%d", packet->type, picture_start_code_name (packet->type), off); + *need_more = FALSE; + switch (packet->type) { case GST_MPEG_VIDEO_PACKET_PICTURE: GST_LOG_OBJECT (mpvparse, "startcode is PICTURE"); @@ -553,6 +556,7 @@ gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse, && (mpvparse->config_flags & FLAG_SEQUENCE_EXT) && !mpvparse->sequenceext.progressive) { if (info->size - off < 2) { /* we need at least two bytes to read the TSN */ + *need_more = TRUE; ret = FALSE; } else { /* TSN is stored in first 10 bits */ @@ -596,6 +600,7 @@ gst_mpegv_parse_handle_frame (GstBaseParse * parse, GstMpegVideoPacket packet; guint8 *data; gint size; + gboolean need_more = FALSE; GstMapInfo map; update_frame_parsing_status (mpvparse, frame); @@ -635,7 +640,7 @@ retry: /* note: initial start code is assumed at offset 0 by subsequent code */ /* examine start code, see if it looks like an initial start code */ - if (gst_mpegv_parse_process_sc (mpvparse, &map, 4, &packet)) { + if (gst_mpegv_parse_process_sc (mpvparse, &map, 4, &packet, &need_more)) { /* found sc */ GST_LOG_OBJECT (mpvparse, "valid start code found"); mpvparse->last_sc = 0; @@ -665,22 +670,18 @@ next: GST_LOG_OBJECT (mpvparse, "next start code at %d", off); if (off < 0) { - /* if draining, take all */ - if (GST_BASE_PARSE_DRAINING (parse)) { - GST_LOG_OBJECT (mpvparse, "draining, accepting all data"); - off = size; - ret = TRUE; - } else { - GST_LOG_OBJECT (mpvparse, "need more data"); - /* resume scan where we left it */ - mpvparse->last_sc = size - 3; - /* request best next available */ - off = G_MAXUINT; - goto exit; - } + off = size - 3; + goto need_more; } else { /* decide whether this startcode ends a frame */ - ret = gst_mpegv_parse_process_sc (mpvparse, &map, off + 4, &packet); + ret = gst_mpegv_parse_process_sc (mpvparse, &map, off + 4, &packet, + &need_more); + /* in rare cases, might need to peek past start code */ + if (need_more) { + GST_LOG_OBJECT (mpvparse, "need more data (past start code"); + ret = FALSE; + goto need_more; + } } if (!ret) @@ -707,6 +708,21 @@ exit: } return flowret; + +need_more: + /* if draining, take all */ + if (GST_BASE_PARSE_DRAINING (parse)) { + GST_LOG_OBJECT (mpvparse, "draining, accepting all data"); + off = size; + ret = TRUE; + } else { + GST_LOG_OBJECT (mpvparse, "need more data"); + /* resume scan where we left it */ + mpvparse->last_sc = off; + /* request best next available */ + off = G_MAXUINT; + } + goto exit; } static void