summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorSeungha Yang <seungha@centricular.com>2021-03-02 17:47:03 +0900
committerSeungha Yang <seungha@centricular.com>2021-03-02 23:26:46 +0900
commit6afb6e65fce7249ae8239e6555a5c382a42b3b90 (patch)
treecc3da2771da0ce0df56a171e2a5c760506de1325 /sys
parent82a4e7e773602c1f6d631007db57ca785a7009d0 (diff)
downloadgstreamer-plugins-bad-6afb6e65fce7249ae8239e6555a5c382a42b3b90.tar.gz
d3d11convert: Add support for border drawing
... and fix wrong resizing when downstream requested PAR value Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2051>
Diffstat (limited to 'sys')
-rw-r--r--sys/d3d11/gstd3d11colorconvert.c288
1 files changed, 250 insertions, 38 deletions
diff --git a/sys/d3d11/gstd3d11colorconvert.c b/sys/d3d11/gstd3d11colorconvert.c
index ac5aa3a4c..5f1cdb124 100644
--- a/sys/d3d11/gstd3d11colorconvert.c
+++ b/sys/d3d11/gstd3d11colorconvert.c
@@ -68,9 +68,12 @@ struct _GstD3D11BaseConvert
GstD3D11VideoProcessor *processor;
gboolean processor_in_use;
- /* used for fallback texture copy */
- D3D11_BOX in_src_box;
- D3D11_BOX out_src_box;
+ /* used for border rendering */
+ RECT in_rect;
+ RECT out_rect;
+
+ gint borders_h;
+ gint borders_w;
};
/**
@@ -1326,6 +1329,103 @@ error:
return FALSE;
}
+/* 16.0 / 255.0 ~= 0.062745 */
+static const float luma_black_level_limited = 0.062745f;
+
+static inline void
+clear_rtv_color_rgb (GstD3D11BaseConvert * self,
+ ID3D11DeviceContext * context_handle, ID3D11RenderTargetView * rtv,
+ gboolean full_range)
+{
+ const FLOAT clear_color_full[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
+ const FLOAT clear_color_limited[4] =
+ { luma_black_level_limited, luma_black_level_limited,
+ luma_black_level_limited, 1.0f
+ };
+ const FLOAT *target;
+
+ if (full_range)
+ target = clear_color_full;
+ else
+ target = clear_color_limited;
+
+ ID3D11DeviceContext_ClearRenderTargetView (context_handle, rtv, target);
+}
+
+static inline void
+clear_rtv_color_vuya (GstD3D11BaseConvert * self,
+ ID3D11DeviceContext * context_handle, ID3D11RenderTargetView * rtv,
+ gboolean full_range)
+{
+ const FLOAT clear_color_full[4] = { 0.5f, 0.5f, 0.0f, 1.0f };
+ const FLOAT clear_color_limited[4] =
+ { 0.5f, 0.5f, luma_black_level_limited, 1.0f };
+ const FLOAT *target;
+
+ if (full_range)
+ target = clear_color_full;
+ else
+ target = clear_color_limited;
+
+ ID3D11DeviceContext_ClearRenderTargetView (context_handle, rtv, target);
+}
+
+static inline void
+clear_rtv_color_luma (GstD3D11BaseConvert * self,
+ ID3D11DeviceContext * context_handle, ID3D11RenderTargetView * rtv,
+ gboolean full_range)
+{
+ const FLOAT clear_color_full[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
+ const FLOAT clear_color_limited[4] =
+ { luma_black_level_limited, luma_black_level_limited,
+ luma_black_level_limited, 1.0f
+ };
+ const FLOAT *target;
+
+ if (full_range)
+ target = clear_color_full;
+ else
+ target = clear_color_limited;
+
+ ID3D11DeviceContext_ClearRenderTargetView (context_handle, rtv, target);
+}
+
+static inline void
+clear_rtv_color_chroma (GstD3D11BaseConvert * self,
+ ID3D11DeviceContext * context_handle, ID3D11RenderTargetView * rtv)
+{
+ const FLOAT clear_color[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
+
+ ID3D11DeviceContext_ClearRenderTargetView (context_handle, rtv, clear_color);
+}
+
+static void
+clear_rtv_color_all (GstD3D11BaseConvert * self, GstVideoInfo * info,
+ ID3D11DeviceContext * context_handle,
+ ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])
+{
+ gint i;
+ gboolean full_range = info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255;
+
+ for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
+ if (!rtv[i])
+ break;
+
+ if (GST_VIDEO_INFO_IS_RGB (info)) {
+ clear_rtv_color_rgb (self, context_handle, rtv[i], full_range);
+ } else {
+ if (GST_VIDEO_INFO_N_PLANES (info) == 1) {
+ clear_rtv_color_vuya (self, context_handle, rtv[i], full_range);
+ } else {
+ if (i == 0)
+ clear_rtv_color_luma (self, context_handle, rtv[i], full_range);
+ else
+ clear_rtv_color_chroma (self, context_handle, rtv[i]);
+ }
+ }
+ }
+}
+
static gboolean
create_shader_output_resource (GstD3D11BaseConvert * self,
GstD3D11Device * device, const GstD3D11Format * format, GstVideoInfo * info)
@@ -1334,6 +1434,7 @@ create_shader_output_resource (GstD3D11BaseConvert * self,
D3D11_RENDER_TARGET_VIEW_DESC view_desc = { 0, };
HRESULT hr;
ID3D11Device *device_handle;
+ ID3D11DeviceContext *context_handle;
ID3D11Texture2D *tex[GST_VIDEO_MAX_PLANES] = { NULL, };
ID3D11RenderTargetView *view[GST_VIDEO_MAX_PLANES] = { NULL, };
gint i;
@@ -1342,6 +1443,7 @@ create_shader_output_resource (GstD3D11BaseConvert * self,
return TRUE;
device_handle = gst_d3d11_device_get_device_handle (device);
+ context_handle = gst_d3d11_device_get_device_context_handle (device);
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
@@ -1414,6 +1516,10 @@ create_shader_output_resource (GstD3D11BaseConvert * self,
}
}
+ gst_d3d11_device_lock (device);
+ clear_rtv_color_all (self, info, context_handle, view);
+ gst_d3d11_device_unlock (device);
+
self->num_output_view = i;
GST_DEBUG_OBJECT (self, "%d render view created", self->num_output_view);
@@ -1446,10 +1552,48 @@ gst_d3d11_base_convert_set_info (GstD3D11BaseFilter * filter,
{
GstD3D11BaseConvert *self = GST_D3D11_BASE_CONVERT (filter);
const GstVideoInfo *unknown_info;
+ gint from_dar_n, from_dar_d, to_dar_n, to_dar_d;
+ D3D11_VIEWPORT view_port;
+ gint border_offset_x = 0;
+ gint border_offset_y = 0;
if (gst_base_transform_is_passthrough (GST_BASE_TRANSFORM (filter)))
return TRUE;
+ if (!gst_util_fraction_multiply (in_info->width,
+ in_info->height, in_info->par_n, in_info->par_d, &from_dar_n,
+ &from_dar_d)) {
+ from_dar_n = from_dar_d = -1;
+ }
+
+ if (!gst_util_fraction_multiply (out_info->width,
+ out_info->height, out_info->par_n, out_info->par_d, &to_dar_n,
+ &to_dar_d)) {
+ to_dar_n = to_dar_d = -1;
+ }
+
+ self->borders_w = self->borders_h = 0;
+ if (to_dar_n != from_dar_n || to_dar_d != from_dar_d) {
+ gint n, d, to_h, to_w;
+
+ if (from_dar_n != -1 && from_dar_d != -1
+ && gst_util_fraction_multiply (from_dar_n, from_dar_d,
+ out_info->par_d, out_info->par_n, &n, &d)) {
+ to_h = gst_util_uint64_scale_int (out_info->width, d, n);
+ if (to_h <= out_info->height) {
+ self->borders_h = out_info->height - to_h;
+ self->borders_w = 0;
+ } else {
+ to_w = gst_util_uint64_scale_int (out_info->height, n, d);
+ g_assert (to_w <= out_info->width);
+ self->borders_h = 0;
+ self->borders_w = out_info->width - to_w;
+ }
+ } else {
+ GST_WARNING_OBJECT (self, "Can't calculate borders");
+ }
+ }
+
gst_d3d11_base_convert_clear_shader_resource (self);
GST_DEBUG_OBJECT (self, "Setup convert with format %s -> %s",
@@ -1460,11 +1604,13 @@ gst_d3d11_base_convert_set_info (GstD3D11BaseFilter * filter,
if (in_info->interlace_mode != out_info->interlace_mode)
goto format_mismatch;
- /* FIXME: add support border */
if (in_info->width == out_info->width && in_info->height == out_info->height
- && in_info->finfo == out_info->finfo) {
+ && in_info->finfo == out_info->finfo && self->borders_w == 0 &&
+ self->borders_h == 0) {
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), TRUE);
return TRUE;
+ } else {
+ gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), FALSE);
}
self->in_d3d11_format =
@@ -1545,20 +1691,45 @@ gst_d3d11_base_convert_set_info (GstD3D11BaseFilter * filter,
}
#endif
- /* setup D3D11_BOX struct for fallback copy */
- self->in_src_box.left = 0;
- self->in_src_box.top = 0;
- self->in_src_box.front = 0;
- self->in_src_box.back = 1;
- self->in_src_box.right = GST_VIDEO_INFO_WIDTH (in_info);
- self->in_src_box.bottom = GST_VIDEO_INFO_HEIGHT (in_info);
-
- self->out_src_box.left = 0;
- self->out_src_box.top = 0;
- self->out_src_box.front = 0;
- self->out_src_box.back = 1;
- self->out_src_box.right = GST_VIDEO_INFO_WIDTH (out_info);
- self->out_src_box.bottom = GST_VIDEO_INFO_HEIGHT (out_info);
+ GST_DEBUG_OBJECT (self, "from=%dx%d (par=%d/%d dar=%d/%d), size %"
+ G_GSIZE_FORMAT " -> to=%dx%d (par=%d/%d dar=%d/%d borders=%d:%d), "
+ "size %" G_GSIZE_FORMAT,
+ in_info->width, in_info->height, in_info->par_n, in_info->par_d,
+ from_dar_n, from_dar_d, in_info->size, out_info->width,
+ out_info->height, out_info->par_n, out_info->par_d, to_dar_n, to_dar_d,
+ self->borders_w, self->borders_h, out_info->size);
+
+ self->in_rect.left = 0;
+ self->in_rect.top = 0;
+ self->in_rect.right = GST_VIDEO_INFO_WIDTH (in_info);
+ self->in_rect.bottom = GST_VIDEO_INFO_HEIGHT (in_info);
+
+ if (self->borders_w) {
+ border_offset_x = self->borders_w / 2;
+ self->out_rect.left = border_offset_x;
+ self->out_rect.right = GST_VIDEO_INFO_WIDTH (out_info) - border_offset_x;
+ } else {
+ self->out_rect.left = 0;
+ self->out_rect.right = GST_VIDEO_INFO_WIDTH (out_info);
+ }
+
+ if (self->borders_h) {
+ border_offset_y = self->borders_h / 2;
+ self->out_rect.top = border_offset_y;
+ self->out_rect.bottom = GST_VIDEO_INFO_HEIGHT (out_info) - border_offset_y;
+ } else {
+ self->out_rect.top = 0;
+ self->out_rect.bottom = GST_VIDEO_INFO_HEIGHT (out_info);
+ }
+
+ view_port.TopLeftX = border_offset_x;
+ view_port.TopLeftY = border_offset_y;
+ view_port.Width = GST_VIDEO_INFO_WIDTH (out_info) - self->borders_w;
+ view_port.Height = GST_VIDEO_INFO_HEIGHT (out_info) - self->borders_h;
+ view_port.MinDepth = 0.0f;
+ view_port.MaxDepth = 1.0f;
+
+ gst_d3d11_color_converter_update_viewport (self->converter, &view_port);
return TRUE;
@@ -1585,38 +1756,54 @@ gst_d3d11_base_convert_prefer_video_processor (GstD3D11BaseConvert * self,
GstMemory *mem;
GstD3D11Memory *dmem;
- if (!self->processor)
+ if (!self->processor) {
+ GST_TRACE_OBJECT (self, "Processor is unavailable");
return FALSE;
+ }
- if (gst_buffer_n_memory (inbuf) != 1 || gst_buffer_n_memory (outbuf) != 1)
+ if (gst_buffer_n_memory (inbuf) != 1 || gst_buffer_n_memory (outbuf) != 1) {
+ GST_TRACE_OBJECT (self, "Num memory objects is mismatched, in: %d, out: %d",
+ gst_buffer_n_memory (inbuf), gst_buffer_n_memory (outbuf));
return FALSE;
+ }
mem = gst_buffer_peek_memory (inbuf, 0);
g_assert (gst_is_d3d11_memory (mem));
dmem = (GstD3D11Memory *) mem;
- if (dmem->device != filter->device)
+ if (dmem->device != filter->device) {
+ GST_TRACE_OBJECT (self, "Input memory belongs to different device");
return FALSE;
+ }
- /* If we can use shader, we prefer to use shader instead of video processor
+ /* If we can use shader, and video processor was not used previously,
+ * we prefer to use shader instead of video processor
* because video processor implementation is vendor dependent
* and not flexible */
if (!self->processor_in_use &&
- gst_d3d11_memory_get_shader_resource_view_size (dmem))
+ gst_d3d11_memory_get_shader_resource_view_size (dmem)) {
+ GST_TRACE_OBJECT (self, "SRV is available");
return FALSE;
+ }
- if (!gst_d3d11_video_processor_get_input_view (self->processor, dmem))
+ if (!gst_d3d11_video_processor_get_input_view (self->processor, dmem)) {
+ GST_TRACE_OBJECT (self, "PIV is unavailable");
return FALSE;
+ }
mem = gst_buffer_peek_memory (outbuf, 0);
g_assert (gst_is_d3d11_memory (mem));
dmem = (GstD3D11Memory *) mem;
- if (dmem->device != filter->device)
+ if (dmem->device != filter->device) {
+ GST_TRACE_OBJECT (self, "Output memory belongs to different device");
return FALSE;
+ }
- if (!gst_d3d11_video_processor_get_output_view (self->processor, dmem))
+ if (!gst_d3d11_video_processor_get_output_view (self->processor, dmem)) {
+ GST_TRACE_OBJECT (self, "POV is unavailable");
return FALSE;
+ }
return TRUE;
}
@@ -1626,7 +1813,6 @@ gst_d3d11_base_convert_transform_using_processor (GstD3D11BaseConvert * self,
GstBuffer * inbuf, GstBuffer * outbuf)
{
GstD3D11Memory *in_mem, *out_mem;
- RECT in_rect, out_rect;
ID3D11VideoProcessorInputView *piv;
ID3D11VideoProcessorOutputView *pov;
@@ -1645,18 +1831,25 @@ gst_d3d11_base_convert_transform_using_processor (GstD3D11BaseConvert * self,
return FALSE;
}
- in_rect.left = 0;
- in_rect.top = 0;
- in_rect.right = self->in_src_box.right;
- in_rect.bottom = self->in_src_box.bottom;
+ /* Clear background color with black */
+ if (self->borders_w || self->borders_h) {
+ GstD3D11BaseFilter *bfilter = GST_D3D11_BASE_FILTER_CAST (self);
+ ID3D11DeviceContext *context_handle =
+ gst_d3d11_device_get_device_context_handle (bfilter->device);
+ ID3D11RenderTargetView *render_view[GST_VIDEO_MAX_PLANES] = { NULL, };
- out_rect.left = 0;
- out_rect.top = 0;
- out_rect.right = self->out_src_box.right;
- out_rect.bottom = self->out_src_box.bottom;
+ if (!gst_d3d11_buffer_get_render_target_view (outbuf, render_view)) {
+ GST_ERROR_OBJECT (self, "ID3D11RenderTargetView is unavailable");
+ return FALSE;
+ }
+
+ gst_d3d11_device_lock (bfilter->device);
+ clear_rtv_color_all (self, &bfilter->out_info, context_handle, render_view);
+ gst_d3d11_device_unlock (bfilter->device);
+ }
return gst_d3d11_video_processor_render (self->processor,
- &in_rect, piv, &out_rect, pov);
+ &self->in_rect, piv, &self->out_rect, pov);
}
static GstFlowReturn
@@ -1670,6 +1863,7 @@ gst_d3d11_base_convert_transform (GstBaseTransform * trans,
ID3D11DeviceContext *context_handle;
ID3D11ShaderResourceView *resource_view[GST_VIDEO_MAX_PLANES] = { NULL, };
ID3D11RenderTargetView *render_view[GST_VIDEO_MAX_PLANES] = { NULL, };
+ ID3D11RenderTargetView **target_rtv;
gint i;
gboolean copy_input = FALSE;
gboolean copy_output = FALSE;
@@ -1701,6 +1895,8 @@ gst_d3d11_base_convert_transform (GstBaseTransform * trans,
self->processor_in_use = TRUE;
+ GST_TRACE_OBJECT (self, "Conversion done by video processor");
+
gst_d3d11_buffer_unmap (inbuf, in_map);
gst_d3d11_buffer_unmap (outbuf, out_map);
@@ -1755,9 +1951,25 @@ gst_d3d11_base_convert_transform (GstBaseTransform * trans,
copy_output = TRUE;
}
+ /* If we need border, clear render target view first */
+ if (copy_output) {
+ target_rtv = self->render_target_view;
+ } else {
+ target_rtv = render_view;
+ }
+
+ /* We need to clear background color as our shader wouldn't touch border
+ * area. Likely output texture was initialized with zeros which is fine for
+ * RGB, but it's not black color in case of YUV */
+ if (self->borders_w || self->borders_h) {
+ gst_d3d11_device_lock (device);
+ clear_rtv_color_all (self, &filter->out_info, context_handle, target_rtv);
+ gst_d3d11_device_unlock (device);
+ }
+
if (!gst_d3d11_color_converter_convert (self->converter,
copy_input ? self->shader_resource_view : resource_view,
- copy_output ? self->render_target_view : render_view, NULL, NULL)) {
+ target_rtv, NULL, NULL)) {
goto conversion_failed;
}