mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-02 00:32:43 +00:00
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
This commit is contained in:
parent
58be5ce16d
commit
830a4aa7f4
1 changed files with 33 additions and 17 deletions
|
@ -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
|
/* for off == 4 initial code; returns TRUE if code starts a frame
|
||||||
* otherwise returns TRUE if code terminates preceding frame */
|
* otherwise returns TRUE if code terminates preceding frame */
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse,
|
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;
|
gboolean ret = FALSE, checkconfig = TRUE;
|
||||||
|
|
||||||
GST_LOG_OBJECT (mpvparse, "process startcode %x (%s) offset:%d", packet->type,
|
GST_LOG_OBJECT (mpvparse, "process startcode %x (%s) offset:%d", packet->type,
|
||||||
picture_start_code_name (packet->type), off);
|
picture_start_code_name (packet->type), off);
|
||||||
|
|
||||||
|
*need_more = FALSE;
|
||||||
|
|
||||||
switch (packet->type) {
|
switch (packet->type) {
|
||||||
case GST_MPEG_VIDEO_PACKET_PICTURE:
|
case GST_MPEG_VIDEO_PACKET_PICTURE:
|
||||||
GST_LOG_OBJECT (mpvparse, "startcode is 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->config_flags & FLAG_SEQUENCE_EXT)
|
||||||
&& !mpvparse->sequenceext.progressive) {
|
&& !mpvparse->sequenceext.progressive) {
|
||||||
if (info->size - off < 2) { /* we need at least two bytes to read the TSN */
|
if (info->size - off < 2) { /* we need at least two bytes to read the TSN */
|
||||||
|
*need_more = TRUE;
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
} else {
|
} else {
|
||||||
/* TSN is stored in first 10 bits */
|
/* TSN is stored in first 10 bits */
|
||||||
|
@ -596,6 +600,7 @@ gst_mpegv_parse_handle_frame (GstBaseParse * parse,
|
||||||
GstMpegVideoPacket packet;
|
GstMpegVideoPacket packet;
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
gint size;
|
gint size;
|
||||||
|
gboolean need_more = FALSE;
|
||||||
GstMapInfo map;
|
GstMapInfo map;
|
||||||
|
|
||||||
update_frame_parsing_status (mpvparse, frame);
|
update_frame_parsing_status (mpvparse, frame);
|
||||||
|
@ -635,7 +640,7 @@ retry:
|
||||||
/* note: initial start code is assumed at offset 0 by subsequent code */
|
/* note: initial start code is assumed at offset 0 by subsequent code */
|
||||||
|
|
||||||
/* examine start code, see if it looks like an initial start 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 */
|
/* found sc */
|
||||||
GST_LOG_OBJECT (mpvparse, "valid start code found");
|
GST_LOG_OBJECT (mpvparse, "valid start code found");
|
||||||
mpvparse->last_sc = 0;
|
mpvparse->last_sc = 0;
|
||||||
|
@ -665,22 +670,18 @@ next:
|
||||||
|
|
||||||
GST_LOG_OBJECT (mpvparse, "next start code at %d", off);
|
GST_LOG_OBJECT (mpvparse, "next start code at %d", off);
|
||||||
if (off < 0) {
|
if (off < 0) {
|
||||||
/* if draining, take all */
|
off = size - 3;
|
||||||
if (GST_BASE_PARSE_DRAINING (parse)) {
|
goto need_more;
|
||||||
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;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* decide whether this startcode ends a frame */
|
/* 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)
|
if (!ret)
|
||||||
|
@ -707,6 +708,21 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
return flowret;
|
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
|
static void
|
||||||
|
|
Loading…
Reference in a new issue