va: basedec: Copy the frames into other_pool if needed.
authorHe Junyan <junyan.he@intel.com>
Wed, 9 Jun 2021 09:14:42 +0000 (17:14 +0800)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Mon, 28 Jun 2021 15:16:39 +0000 (15:16 +0000)
If decoder's crop_top/left value > 0 and the downstream does not
support the VideoCropMeta, we need to manually copy the frames
into the other_pool and output it.

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

sys/va/gstvabasedec.c
sys/va/gstvabasedec.h

index 8cb9127..0e72795 100644 (file)
@@ -85,6 +85,8 @@ gst_va_base_dec_stop (GstVideoDecoder * decoder)
     gst_buffer_pool_set_active (base->other_pool, FALSE);
   gst_clear_object (&base->other_pool);
 
+  g_clear_pointer (&base->convert, gst_video_converter_free);
+
   return GST_VIDEO_DECODER_CLASS (GST_VA_BASE_DEC_GET_PARENT_CLASS
       (decoder))->stop (decoder);
 }
@@ -817,6 +819,66 @@ bail:
   gst_clear_caps (&preferred_caps);
 }
 
+static gboolean
+_copy_buffer_and_apply_video_crop (GstVaBaseDec * base,
+    GstVideoFrame * src_frame, GstVideoFrame * dest_frame,
+    GstVideoCropMeta * video_crop)
+{
+  GstVideoInfo dst_info = dest_frame->info;
+
+  dst_info.fps_n = src_frame->info.fps_n;
+  dst_info.fps_d = src_frame->info.fps_d;
+
+  if (base->convert) {
+    gboolean new_convert = FALSE;
+    gint x = 0, y = 0, width = 0, height = 0;
+    const GstStructure *config = gst_video_converter_get_config (base->convert);
+
+    if (!gst_structure_get_int (config, GST_VIDEO_CONVERTER_OPT_SRC_X, &x)
+        || !gst_structure_get_int (config, GST_VIDEO_CONVERTER_OPT_SRC_Y, &y)
+        || !gst_structure_get_int (config, GST_VIDEO_CONVERTER_OPT_SRC_WIDTH,
+            &width)
+        || !gst_structure_get_int (config, GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT,
+            &height))
+      new_convert = TRUE;
+
+    new_convert |= (video_crop->x != x);
+    new_convert |= (video_crop->y != y);
+    new_convert |= (video_crop->width != width);
+    new_convert |= (video_crop->height != height);
+
+    /* No need to check dest, it always has (0,0) -> (width, height) */
+
+    if (new_convert)
+      g_clear_pointer (&base->convert, gst_video_converter_free);
+  }
+
+  if (!base->convert) {
+    base->convert = gst_video_converter_new (&src_frame->info, &dst_info,
+        gst_structure_new ("options",
+            GST_VIDEO_CONVERTER_OPT_MATRIX_MODE,
+            GST_TYPE_VIDEO_MATRIX_MODE, GST_VIDEO_MATRIX_MODE_NONE,
+            GST_VIDEO_CONVERTER_OPT_SRC_X, G_TYPE_INT, video_crop->x,
+            GST_VIDEO_CONVERTER_OPT_SRC_Y, G_TYPE_INT, video_crop->y,
+            GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, G_TYPE_INT, video_crop->width,
+            GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT, G_TYPE_INT, video_crop->height,
+            GST_VIDEO_CONVERTER_OPT_DEST_X, G_TYPE_INT, 0,
+            GST_VIDEO_CONVERTER_OPT_DEST_Y, G_TYPE_INT, 0,
+            GST_VIDEO_CONVERTER_OPT_DEST_WIDTH, G_TYPE_INT, video_crop->width,
+            GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT, G_TYPE_INT, video_crop->height,
+            NULL));
+
+    if (!base->convert) {
+      GST_WARNING_OBJECT (base, "failed to create a video convert");
+      return FALSE;
+    }
+  }
+
+  gst_video_converter_frame (base->convert, src_frame, dest_frame);
+
+  return TRUE;
+}
+
 gboolean
 gst_va_base_dec_copy_output_buffer (GstVaBaseDec * base,
     GstVideoCodecFrame * codec_frame)
@@ -825,7 +887,8 @@ gst_va_base_dec_copy_output_buffer (GstVaBaseDec * base,
   GstVideoFrame dest_frame;
   GstVideoInfo dest_vinfo;
   GstVideoInfo *src_vinfo;
-  GstBuffer *buffer;
+  GstBuffer *buffer = NULL;
+  GstVideoCropMeta *video_crop;
   GstFlowReturn ret;
 
   g_return_val_if_fail (base && base->output_state, FALSE);
@@ -843,25 +906,34 @@ gst_va_base_dec_copy_output_buffer (GstVaBaseDec * base,
   ret = gst_buffer_pool_acquire_buffer (base->other_pool, &buffer, NULL);
   if (ret != GST_FLOW_OK)
     goto fail;
-
   if (!gst_video_frame_map (&src_frame, src_vinfo, codec_frame->output_buffer,
           GST_MAP_READ))
     goto fail;
-
   if (!gst_video_frame_map (&dest_frame, &dest_vinfo, buffer, GST_MAP_WRITE)) {
     gst_video_frame_unmap (&src_frame);
     goto fail;
   }
 
-  /* gst_video_frame_copy can crop this, but does not know, so let
-   * make it think it's all right */
-  GST_VIDEO_INFO_WIDTH (&src_frame.info) = base->width;
-  GST_VIDEO_INFO_HEIGHT (&src_frame.info) = base->height;
-
-  if (!gst_video_frame_copy (&dest_frame, &src_frame)) {
-    gst_video_frame_unmap (&src_frame);
-    gst_video_frame_unmap (&dest_frame);
-    goto fail;
+  video_crop = gst_buffer_get_video_crop_meta (codec_frame->output_buffer);
+  if (video_crop) {
+    if (!_copy_buffer_and_apply_video_crop (base,
+            &src_frame, &dest_frame, video_crop)) {
+      gst_video_frame_unmap (&src_frame);
+      gst_video_frame_unmap (&dest_frame);
+      GST_ERROR_OBJECT (base, "fail to apply the video crop.");
+      goto fail;
+    }
+  } else {
+    /* gst_video_frame_copy can crop this, but does not know, so let
+     * make it think it's all right */
+    GST_VIDEO_INFO_WIDTH (&src_frame.info) = base->width;
+    GST_VIDEO_INFO_HEIGHT (&src_frame.info) = base->height;
+
+    if (!gst_video_frame_copy (&dest_frame, &src_frame)) {
+      gst_video_frame_unmap (&src_frame);
+      gst_video_frame_unmap (&dest_frame);
+      goto fail;
+    }
   }
 
   gst_video_frame_unmap (&src_frame);
@@ -872,6 +944,9 @@ gst_va_base_dec_copy_output_buffer (GstVaBaseDec * base,
   return TRUE;
 
 fail:
+  if (buffer)
+    gst_buffer_unref (buffer);
+
   GST_ERROR_OBJECT (base, "Failed copy output buffer.");
   return FALSE;
 }
index 3050640..5f53b4a 100644 (file)
@@ -76,6 +76,7 @@ struct _GstVaBaseDec
   gboolean copy_frames;
 
   gboolean apply_video_crop;
+  GstVideoConverter *convert;
 };
 
 struct _GstVaBaseDecClass