From f63a70966e6ce11ab0fb64964e356394c9c97d13 Mon Sep 17 00:00:00 2001 From: He Junyan Date: Thu, 9 Jan 2025 23:42:14 +0800 Subject: [PATCH] av1parse: Handle the padding OBU correctly The current av1parse can not find the edge of frame correctly if there is padding OBUs inside the stream. We now use a flag seen_non_padding to check whether we see some valid data after a data push. Then the padding OBUs will be the part of the new frame. We also refine the code logic to make the code more readable. Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/4044 Part-of: --- .../gst/videoparsers/gstav1parse.c | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/subprojects/gst-plugins-bad/gst/videoparsers/gstav1parse.c b/subprojects/gst-plugins-bad/gst/videoparsers/gstav1parse.c index 9134a0fb54..bf9b277062 100644 --- a/subprojects/gst-plugins-bad/gst/videoparsers/gstav1parse.c +++ b/subprojects/gst-plugins-bad/gst/videoparsers/gstav1parse.c @@ -139,6 +139,7 @@ struct _GstAV1Parse gboolean header; gboolean keyframe; gboolean show_frame; + gboolean seen_non_padding; GstClockTime buffer_pts; GstClockTime buffer_dts; @@ -333,6 +334,7 @@ gst_av1_parse_reset (GstAV1Parse * self) self->last_parsed_offset = 0; self->highest_spatial_id = 0; self->first_frame = TRUE; + self->seen_non_padding = FALSE; gst_av1_parse_reset_obu_data_state (self); g_clear_pointer (&self->colorimetry, g_free); g_clear_pointer (&self->parser, gst_av1_parser_free); @@ -1150,6 +1152,8 @@ gst_av1_parse_push_data (GstAV1Parse * self, GstBaseParseFrame * frame, GST_LOG_OBJECT (self, "comsumed %d, output one buffer with size %" G_GSSIZE_FORMAT, finish_sz, sz); ret = gst_base_parse_finish_frame (GST_BASE_PARSE (self), frame, finish_sz); + + self->seen_non_padding = FALSE; } return ret; @@ -1594,15 +1598,25 @@ gst_av1_parse_handle_one_obu (GstAV1Parse * self, GstAV1OBU * obu, if (obu->obu_type == GST_AV1_OBU_TEMPORAL_DELIMITER) { gst_av1_parse_reset_obu_data_state (self); + /* Let the leading padding OBUs be the part of the new TD. */ + if (!self->seen_non_padding) + goto out; + if (check_new_tu) { *check_new_tu = TRUE; res = GST_AV1_PARSER_OK; - goto out; } + + /* Start a new TD should also complete the current frame. */ + *frame_complete = TRUE; + + goto out; } - if (obu->obu_type == GST_AV1_OBU_SEQUENCE_HEADER) + if (obu->obu_type == GST_AV1_OBU_SEQUENCE_HEADER) { self->header = TRUE; + goto out; + } if (obu->obu_type == GST_AV1_OBU_FRAME_HEADER || obu->obu_type == GST_AV1_OBU_FRAME @@ -1673,6 +1687,9 @@ out: } } + if (obu->obu_type != GST_AV1_OBU_PADDING) + self->seen_non_padding = TRUE; + return res; } @@ -1761,6 +1778,7 @@ gst_av1_parse_handle_obu_to_obu (GstBaseParse * parse, GST_LOG_OBJECT (self, "Output one buffer with size %d", consumed); ret = gst_base_parse_finish_frame (parse, frame, consumed); + self->seen_non_padding = FALSE; *skipsize = 0; out: @@ -1819,29 +1837,6 @@ again: if (res != GST_AV1_PARSER_OK) break; - if (obu.obu_type == GST_AV1_OBU_TEMPORAL_DELIMITER - && consumed_before_push > 0) { - GST_DEBUG_OBJECT (self, "Encounter TD inside one %s aligned" - " buffer, should not happen normally.", - gst_av1_parse_alignment_to_string (self->in_align)); - - if (self->in_align == GST_AV1_PARSE_ALIGN_TEMPORAL_UNIT_ANNEX_B) - gst_av1_parser_reset_annex_b (self->parser); - - /* Not include this TD obu, it should belong to the next TU or frame, - we push all the data we already got. */ - gst_av1_parse_create_subframe (frame, &subframe, buffer); - ret = gst_av1_parse_push_data (self, &subframe, - consumed_before_push, TRUE); - if (ret != GST_FLOW_OK) - goto out; - - /* Begin to find the next. */ - frame_complete = FALSE; - consumed_before_push = 0; - continue; - } - gst_av1_parse_cache_one_obu (self, buffer, &obu, map_info.data + offset, consumed, frame_complete); @@ -1899,8 +1894,8 @@ again: /* If the total buffer exhausted but frame is not complete, we just push the left data and consider it as a frame. */ - if (consumed_before_push > 0 && !frame_complete - && self->align == GST_AV1_PARSE_ALIGN_FRAME) { + if (consumed_before_push > 0 && !frame_complete && self->seen_non_padding && + self->align == GST_AV1_PARSE_ALIGN_FRAME) { g_assert (offset >= map_info.size); /* Warning and still consider the frame is complete */ GST_WARNING_OBJECT (self, "Exhaust the buffer but still incomplete frame," @@ -1908,7 +1903,8 @@ again: gst_av1_parse_alignment_to_string (self->in_align)); } - ret = gst_av1_parse_push_data (self, frame, consumed_before_push, TRUE); + if (self->seen_non_padding) + ret = gst_av1_parse_push_data (self, frame, consumed_before_push, TRUE); out: gst_buffer_unmap (buffer, &map_info); @@ -2149,6 +2145,7 @@ again: out: gst_av1_parse_reset_obu_data_state (self); + self->seen_non_padding = FALSE; gst_buffer_unmap (buffer, &map_info); gst_buffer_unref (buffer); return ret; @@ -2181,6 +2178,7 @@ gst_av1_parse_handle_frame (GstBaseParse * parse, GST_LOG_OBJECT (self, "parsing new frame"); gst_adapter_clear (self->cache_out); gst_adapter_clear (self->frame_cache); + self->seen_non_padding = FALSE; self->last_parsed_offset = 0; self->header = FALSE; self->keyframe = FALSE;