av1parse: push all data once when input alignment not smaller than output.
authorHe Junyan <junyan.he@intel.com>
Fri, 14 Oct 2022 07:46:16 +0000 (15:46 +0800)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 21 Oct 2022 11:16:13 +0000 (11:16 +0000)
When the incoming data has big alignment than the output, we do not need to
call finish_frame() and exit the current handle_frame() for each splitted
frame. We can push them all at one shot with in one handle_frame(), whcih
may improve the performance and can help us to find the edge of TU.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3182>

subprojects/gst-plugins-bad/gst/videoparsers/gstav1parse.c

index 73c45f5..2299afc 100644 (file)
@@ -1562,6 +1562,19 @@ out:
   return ret;
 }
 
+static void
+gst_av1_parse_create_subframe (GstBaseParseFrame * frame,
+    GstBaseParseFrame * subframe, GstBuffer * buffer)
+{
+  gst_base_parse_frame_init (subframe);
+  subframe->flags |= frame->flags;
+  subframe->offset = frame->offset;
+  subframe->overhead = frame->overhead;
+  /* Just ref the input buffer. The base parse will check that
+     pointer, and it will be replaced by its out_buffer later. */
+  subframe->buffer = gst_buffer_ref (buffer);
+}
+
 static GstFlowReturn
 gst_av1_parse_handle_to_small_and_equal_align (GstBaseParse * parse,
     GstBaseParseFrame * frame, gint * skipsize)
@@ -1572,47 +1585,69 @@ gst_av1_parse_handle_to_small_and_equal_align (GstBaseParse * parse,
   GstFlowReturn ret = GST_FLOW_OK;
   GstAV1ParserResult res = GST_AV1_PARSER_INVALID_OPERATION;
   GstBuffer *buffer = gst_buffer_ref (frame->buffer);
-  guint32 total_consumed, consumed;
+  guint32 offset, consumed_before_push, consumed;
   gboolean frame_complete;
+  GstBaseParseFrame subframe;
 
   if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
     GST_ERROR_OBJECT (parse, "Couldn't map incoming buffer");
     return GST_FLOW_ERROR;
   }
 
-  total_consumed = 0;
+  consumed_before_push = 0;
+  offset = 0;
   frame_complete = FALSE;
 again:
-  while (total_consumed < map_info.size) {
+  while (offset < map_info.size) {
     res = gst_av1_parser_identify_one_obu (self->parser,
-        map_info.data + total_consumed, map_info.size - total_consumed,
-        &obu, &consumed);
+        map_info.data + offset, map_info.size - offset, &obu, &consumed);
     if (res == GST_AV1_PARSER_OK)
       res = gst_av1_parse_handle_one_obu (self, &obu, &frame_complete, NULL);
     if (res != GST_AV1_PARSER_OK)
       break;
 
-    if (obu.obu_type == GST_AV1_OBU_TEMPORAL_DELIMITER && total_consumed) {
+    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));
-      frame_complete = TRUE;
+
       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 */
-      break;
+
+      /* 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 + total_consumed, consumed, frame_complete);
+        map_info.data + offset, consumed, frame_complete);
 
-    total_consumed += consumed;
+    offset += consumed;
+    consumed_before_push += consumed;
 
-    if (self->align == GST_AV1_PARSE_ALIGN_OBU)
-      break;
+    if ((self->align == GST_AV1_PARSE_ALIGN_OBU) ||
+        (self->align == GST_AV1_PARSE_ALIGN_FRAME && frame_complete)) {
+      gst_av1_parse_create_subframe (frame, &subframe, buffer);
+      ret = gst_av1_parse_push_data (self, &subframe,
+          consumed_before_push, frame_complete);
+      if (ret != GST_FLOW_OK)
+        goto out;
 
-    if (self->align == GST_AV1_PARSE_ALIGN_FRAME && frame_complete)
-      break;
+      /* Begin to find the next. */
+      frame_complete = FALSE;
+      consumed_before_push = 0;
+      continue;
+    }
   }
 
   if (res == GST_AV1_PARSER_BITSTREAM_ERROR ||
@@ -1638,7 +1673,7 @@ again:
     goto out;
   } else if (res == GST_AV1_PARSER_DROP) {
     GST_DEBUG_OBJECT (parse, "Drop %d data", consumed);
-    total_consumed += consumed;
+    offset += consumed;
     gst_av1_parse_reset_obu_data_state (self);
     res = GST_AV1_PARSER_OK;
     goto again;
@@ -1649,18 +1684,18 @@ again:
     goto out;
   }
 
-  g_assert (total_consumed >= map_info.size || frame_complete
-      || self->align == GST_AV1_PARSE_ALIGN_OBU);
-
-  if (total_consumed >= map_info.size && !frame_complete
+  /* 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) {
-    /* Warning and still consider this frame as complete */
+    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,"
         " should not happend in %s alignment",
         gst_av1_parse_alignment_to_string (self->in_align));
   }
 
-  ret = gst_av1_parse_push_data (self, frame, total_consumed, frame_complete);
+  ret = gst_av1_parse_push_data (self, frame, consumed_before_push, TRUE);
 
 out:
   gst_buffer_unmap (buffer, &map_info);