jpegparse: reset parse state when the SOI is not the first marker

There may be garbage or some bits before a SOI comes in some problematic
mjpeg streams. For example, some network error may cause the EOI marker
of the previous frame lost, and when the new frame's SOI comes, we still
use the state of the last frame, which will generate errors.

For this kind of frames without EOI, if that frame already has some data
(the SOS segment is detected), we still push it as a frame with CORRUPTED
flag set. But if not, we just discard all the data before the new SOI.

Co-Authored-By: Víctor Jáquez <vjaquez@igalia.com>
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4039>
This commit is contained in:
He Junyan 2023-02-12 22:37:01 +08:00 committed by GStreamer Marge Bot
parent dafc024ed0
commit d8feddcc0c

View file

@ -676,10 +676,14 @@ gst_jpeg_parse_set_new_caps (GstJpegParse * parse)
} }
static GstFlowReturn static GstFlowReturn
gst_jpeg_parse_push_frame (GstJpegParse * parse, GstBaseParseFrame * frame, gst_jpeg_parse_finish_frame (GstJpegParse * parse, GstBaseParseFrame * frame,
gint size) gint size)
{ {
GstBaseParse *bparse = GST_BASE_PARSE (parse); GstBaseParse *bparse = GST_BASE_PARSE (parse);
GstFlowReturn ret;
if (parse->tags)
gst_base_parse_merge_tags (bparse, parse->tags, GST_TAG_MERGE_REPLACE);
if (!gst_jpeg_parse_set_new_caps (parse)) if (!gst_jpeg_parse_set_new_caps (parse))
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
@ -690,7 +694,11 @@ gst_jpeg_parse_push_frame (GstJpegParse * parse, GstBaseParseFrame * frame,
GST_WARNING_OBJECT (parse, "Potentially invalid picture"); GST_WARNING_OBJECT (parse, "Potentially invalid picture");
} }
return gst_base_parse_finish_frame (bparse, frame, size); ret = gst_base_parse_finish_frame (bparse, frame, size);
gst_jpeg_parse_reset (parse);
return ret;
} }
static GstFlowReturn static GstFlowReturn
@ -745,32 +753,41 @@ gst_jpeg_parse_handle_frame (GstBaseParse * bparse, GstBaseParseFrame * frame,
switch (marker) { switch (marker) {
case GST_JPEG_MARKER_SOI: case GST_JPEG_MARKER_SOI:
parse->state |= GST_JPEG_PARSER_STATE_GOT_SOI; /* This means that new SOI comes without an previous EOI. */
/* unset tags */
gst_base_parse_merge_tags (bparse, NULL, GST_TAG_MERGE_UNDEFINED);
/* remove all previous bytes */
if (offset > 2) { if (offset > 2) {
/* If already some data segment parsed, push it as a frame. */
if (valid_state (parse->state, GST_JPEG_PARSER_STATE_GOT_SOS)) {
gst_buffer_unmap (frame->buffer, &mapinfo);
frame->out_buffer = gst_buffer_copy_region (frame->buffer,
GST_BUFFER_COPY_ALL, 0, seg.offset - 2);
GST_MINI_OBJECT_FLAGS (frame->out_buffer) |=
GST_BUFFER_FLAG_CORRUPTED;
GST_DEBUG_OBJECT (parse, "Push a frame without EOI, size %d",
seg.offset - 2);
return gst_jpeg_parse_finish_frame (parse, frame, seg.offset - 2);
}
gst_jpeg_parse_reset (parse);
parse->state |= GST_JPEG_PARSER_STATE_GOT_SOI;
/* unset tags */
gst_base_parse_merge_tags (bparse, NULL, GST_TAG_MERGE_UNDEFINED);
*skipsize = offset - 2; *skipsize = offset - 2;
GST_DEBUG_OBJECT (parse, "skipping %d bytes before SOI", *skipsize); GST_DEBUG_OBJECT (parse, "skipping %d bytes before SOI", *skipsize);
parse->last_offset = 2; parse->last_offset = 2;
goto beach; goto beach;
} }
/* unset tags */
gst_base_parse_merge_tags (bparse, NULL, GST_TAG_MERGE_UNDEFINED);
parse->state |= GST_JPEG_PARSER_STATE_GOT_SOI;
break; break;
case GST_JPEG_MARKER_EOI:{ case GST_JPEG_MARKER_EOI:
GstFlowReturn ret;
gst_buffer_unmap (frame->buffer, &mapinfo); gst_buffer_unmap (frame->buffer, &mapinfo);
return gst_jpeg_parse_finish_frame (parse, frame, seg.offset);
if (parse->tags) { break;
gst_base_parse_merge_tags (bparse, parse->tags,
GST_TAG_MERGE_REPLACE);
}
ret = gst_jpeg_parse_push_frame (parse, frame, seg.offset);
gst_jpeg_parse_reset (parse);
return ret;
}
case GST_JPEG_MARKER_SOS: case GST_JPEG_MARKER_SOS:
if (!valid_state (parse->state, GST_JPEG_PARSER_STATE_GOT_SOF)) if (!valid_state (parse->state, GST_JPEG_PARSER_STATE_GOT_SOF))
GST_WARNING_OBJECT (parse, "SOS marker without SOF one"); GST_WARNING_OBJECT (parse, "SOS marker without SOF one");