codecs: av1dec: Fix to output frame with highest spatial layer
authorMengkejiergeli Ba <mengkejiergeli.ba@intel.com>
Fri, 20 Aug 2021 05:28:51 +0000 (13:28 +0800)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 27 Aug 2021 15:27:31 +0000 (15:27 +0000)
During the output process, if there are multiple frames in a TU (i.e. multi-spatial
layers case), only one frame with the highest spatial layer id should be selected
according to av1 spec. The highest spatial layer id is obtained from idc value of
the operating point.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2475>

gst-libs/gst/codecs/gstav1decoder.c

index 68578e0b420255b123b622aff6b3a49ec5268f2b..7f7b4141fc4e97dcb9b369f8b5416b22d19cc282 100644 (file)
@@ -52,6 +52,18 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstAV1Decoder, gst_av1_decoder,
     GST_DEBUG_CATEGORY_INIT (gst_av1_decoder_debug, "av1decoder", 0,
         "AV1 Video Decoder"));
 
+static gint
+_floor_log2 (guint32 x)
+{
+  gint s = 0;
+
+  while (x != 0) {
+    x = x >> 1;
+    s++;
+  }
+  return s - 1;
+}
+
 static gboolean gst_av1_decoder_start (GstVideoDecoder * decoder);
 static gboolean gst_av1_decoder_stop (GstVideoDecoder * decoder);
 static gboolean gst_av1_decoder_set_format (GstVideoDecoder * decoder,
@@ -591,9 +603,19 @@ out:
   if (ret == GST_FLOW_OK) {
     if (priv->current_picture->frame_hdr.show_frame ||
         priv->current_picture->frame_hdr.show_existing_frame) {
-      g_assert (klass->output_picture);
-      /* transfer ownership of frame and picture */
-      ret = klass->output_picture (self, frame, priv->current_picture);
+      /* Only output one frame with the highest spatial id from each TU
+       * when there are multiple spatial layers.
+       */
+      if (priv->parser->state.operating_point_idc &&
+          obu.header.obu_spatial_id <
+          _floor_log2 (priv->parser->state.operating_point_idc >> 8)) {
+        gst_av1_picture_unref (priv->current_picture);
+        gst_video_decoder_release_frame (decoder, frame);
+      } else {
+        g_assert (klass->output_picture);
+        /* transfer ownership of frame and picture */
+        ret = klass->output_picture (self, frame, priv->current_picture);
+      }
     } else {
       GST_LOG_OBJECT (self, "Decode only picture %p", priv->current_picture);
       GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);