d3d11videosink: Add support for crop meta
authorSeungha Yang <seungha@centricular.com>
Sat, 18 Sep 2021 14:37:20 +0000 (23:37 +0900)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Mon, 27 Sep 2021 16:29:09 +0000 (16:29 +0000)
... when upstream element is d3d11.

Note that, if upstream element is not d3d11, crop meta is almost
pointless since d3d11videosink will upload video frame to GPU memory
in any case.

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

subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp
subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp

index 274b6b1a7d5e68c035b10aec4425b8acb494c787..a7d80c8173b06bd6afcb93334b68a48e75b5137c 100644 (file)
@@ -905,6 +905,12 @@ gst_d3d11_video_sink_propose_allocation (GstBaseSink * sink, GstQuery * query)
       gst_buffer_pool_config_get_params (config, nullptr, &size, nullptr,
           nullptr);
       gst_structure_free (config);
+
+      /* In case of system memory, we will upload video frame to GPU memory,
+       * (which is copy in any case), so crop meta support for system memory
+       * is almost pointless */
+      gst_query_add_allocation_meta (query,
+          GST_VIDEO_CROP_META_API_TYPE, nullptr);
     }
   }
 
@@ -1068,6 +1074,7 @@ gst_d3d11_video_sink_get_fallback_buffer (GstD3D11VideoSink * self,
   GstBuffer *outbuf = NULL;
   ID3D11ShaderResourceView *view[GST_VIDEO_MAX_PLANES];
   GstVideoOverlayCompositionMeta *compo_meta;
+  GstVideoCropMeta *crop_meta;
 
   if (!self->fallback_pool ||
       !gst_buffer_pool_set_active (self->fallback_pool, TRUE) ||
@@ -1098,6 +1105,17 @@ gst_d3d11_video_sink_get_fallback_buffer (GstD3D11VideoSink * self,
   if (compo_meta)
     gst_buffer_add_video_overlay_composition_meta (outbuf, compo_meta->overlay);
 
+  /* And copy crop meta as well */
+  crop_meta = gst_buffer_get_video_crop_meta (inbuf);
+  if (crop_meta) {
+    GstVideoCropMeta *new_crop_meta = gst_buffer_add_video_crop_meta (outbuf);
+
+    new_crop_meta->x = crop_meta->x;
+    new_crop_meta->y = crop_meta->y;
+    new_crop_meta->width = crop_meta->width;
+    new_crop_meta->height = crop_meta->height;
+  }
+
   *fallback_buf = outbuf;
 
   return TRUE;
index 6eb53f318cba8249ff304e5b55e87d730ffeebe1..00f98be924baea0a3fe0207551ffbda4ea3ac180 100644 (file)
@@ -828,12 +828,13 @@ gst_d3d11_window_buffer_ensure_processor_input (GstD3D11Window * self,
 
 static gboolean
 gst_d3d11_window_do_processor (GstD3D11Window * self,
-    ID3D11VideoProcessorInputView * piv, ID3D11VideoProcessorOutputView * pov)
+    ID3D11VideoProcessorInputView * piv, ID3D11VideoProcessorOutputView * pov,
+    RECT * input_rect)
 {
   gboolean ret;
 
   ret = gst_d3d11_video_processor_render_unlocked (self->processor,
-      &self->input_rect, piv, &self->render_rect, pov);
+      input_rect, piv, &self->render_rect, pov);
   if (!ret) {
     GST_ERROR_OBJECT (self, "Couldn't render to backbuffer using processor");
   } else {
@@ -847,8 +848,13 @@ gst_d3d11_window_do_processor (GstD3D11Window * self,
 static gboolean
 gst_d3d11_window_do_convert (GstD3D11Window * self,
     ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],
-    ID3D11RenderTargetView * rtv)
+    ID3D11RenderTargetView * rtv, RECT * input_rect)
 {
+  if (!gst_d3d11_converter_update_src_rect (self->converter, input_rect)) {
+    GST_ERROR_OBJECT (self, "Failed to update src rect");
+    return FALSE;
+  }
+
   if (!gst_d3d11_converter_convert_unlocked (self->converter,
           srv, &rtv, NULL, NULL)) {
     GST_ERROR_OBJECT (self, "Couldn't render to backbuffer using converter");
@@ -880,6 +886,8 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer,
     gboolean can_convert = FALSE;
     gboolean can_process = FALSE;
     gboolean convert_ret = FALSE;
+    RECT input_rect = self->input_rect;
+    GstVideoCropMeta *crop_meta;
 
     /* Map memory in any case so that we can upload pending stage texture */
     if (!gst_d3d11_buffer_map (buffer, device_handle, infos, GST_MAP_READ)) {
@@ -898,6 +906,29 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer,
       return GST_FLOW_ERROR;
     }
 
+    crop_meta = gst_buffer_get_video_crop_meta (buffer);
+    /* Do minimal validate */
+    if (crop_meta) {
+      ID3D11Texture2D *texture = (ID3D11Texture2D *) infos[0].data;
+      D3D11_TEXTURE2D_DESC desc = { 0, };
+
+      texture->GetDesc (&desc);
+
+      if (desc.Width < crop_meta->x + crop_meta->width ||
+          desc.Height < crop_meta->y + crop_meta->height) {
+        GST_WARNING_OBJECT (self, "Invalid crop meta, ignore");
+
+        crop_meta = nullptr;
+      }
+    }
+
+    if (crop_meta) {
+      input_rect.left = crop_meta->x;
+      input_rect.right = crop_meta->x + crop_meta->width;
+      input_rect.top = crop_meta->y;
+      input_rect.bottom = crop_meta->y + crop_meta->height;
+    }
+
     if (self->first_present) {
       D3D11_VIEWPORT viewport;
 
@@ -919,11 +950,11 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer,
      * 3) otherwise, use processor
      */
     if (can_process && self->processor_in_use) {
-      convert_ret = gst_d3d11_window_do_processor (self, piv, pov);
+      convert_ret = gst_d3d11_window_do_processor (self, piv, pov, &input_rect);
     } else if (can_convert) {
-      convert_ret = gst_d3d11_window_do_convert (self, srv, rtv);
+      convert_ret = gst_d3d11_window_do_convert (self, srv, rtv, &input_rect);
     } else if (can_process) {
-      convert_ret = gst_d3d11_window_do_processor (self, piv, pov);
+      convert_ret = gst_d3d11_window_do_processor (self, piv, pov, &input_rect);
     } else {
       g_assert_not_reached ();
       ret = GST_FLOW_ERROR;