d3d11videosink: Remove resizing window hack and unify resizing flow

In earlier implementation of d3d11videosink where no shader was implemented,
the aspect ratio and render size were adjusted by manipulating the backbuffer size
with unintuitive formula. Since now we do color conversion and resize using
shader, we can remove the hack.
This commit is contained in:
Seungha Yang 2019-12-15 16:23:00 +09:00
parent 61cb6b2bbe
commit 9dada90108
4 changed files with 94 additions and 184 deletions

View file

@ -338,7 +338,7 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
if (!gst_d3d11_window_prepare (self->window, GST_VIDEO_SINK_WIDTH (self),
GST_VIDEO_SINK_HEIGHT (self), video_par_n, video_par_d,
caps, &self->need_srv, &error)) {
caps, &error)) {
GstMessage *error_msg;
GST_ERROR_OBJECT (self, "cannot create swapchain");
@ -360,7 +360,7 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
gst_buffer_pool_config_set_params (config,
caps, GST_VIDEO_INFO_SIZE (&self->info), 0, 2);
if (self->need_srv) {
{
GstD3D11AllocationParams *d3d11_params;
d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
@ -525,7 +525,7 @@ gst_d3d11_video_sink_propose_allocation (GstBaseSink * sink, GstQuery * query)
if (need_pool) {
gint i;
GstCaps *render_caps;
GstD3D11AllocationParams *d3d11_params;
GST_DEBUG_OBJECT (self, "create new pool");
@ -534,34 +534,22 @@ gst_d3d11_video_sink_propose_allocation (GstBaseSink * sink, GstQuery * query)
gst_buffer_pool_config_set_params (config, caps, size, 2,
DXGI_MAX_SWAP_CHAIN_BUFFERS);
render_caps = gst_d3d11_device_get_supported_caps (self->device,
D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_DISPLAY);
/* if we need conversion, request shader resource view */
if (render_caps && !gst_caps_can_intersect (caps, render_caps)) {
GstD3D11AllocationParams *d3d11_params;
GST_DEBUG_OBJECT (self,
"upstream format %s is not display foramt, need shader resource",
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&info)));
d3d11_params =
gst_buffer_pool_config_get_d3d11_allocation_params (config);
if (!d3d11_params) {
d3d11_params = gst_d3d11_allocation_params_new (&info,
GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT, D3D11_USAGE_DEFAULT,
D3D11_BIND_SHADER_RESOURCE);
} else {
/* Set bind flag */
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) {
d3d11_params->desc[i].BindFlags |= D3D11_BIND_SHADER_RESOURCE;
}
d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
if (!d3d11_params) {
d3d11_params = gst_d3d11_allocation_params_new (&info,
GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT, D3D11_USAGE_DEFAULT,
D3D11_BIND_SHADER_RESOURCE);
} else {
/* Set bind flag */
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) {
d3d11_params->desc[i].BindFlags |= D3D11_BIND_SHADER_RESOURCE;
}
gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
gst_d3d11_allocation_params_free (d3d11_params);
}
gst_clear_caps (&render_caps);
gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
gst_d3d11_allocation_params_free (d3d11_params);
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_META);
if (!gst_buffer_pool_set_config (pool, config)) {
g_object_unref (pool);
@ -672,7 +660,7 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
break;
}
if (self->need_srv && !gst_d3d11_memory_ensure_shader_resource_view (dmem)) {
if (!gst_d3d11_memory_ensure_shader_resource_view (dmem)) {
GST_LOG_OBJECT (sink,
"shader resource view is unavailable, need fallback");
render_buf = NULL;
@ -742,8 +730,7 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
GST_MAP_READ | GST_MAP_D3D11);
gst_memory_unmap (GST_MEMORY_CAST (dmem), &info);
if (self->need_srv &&
!gst_d3d11_memory_ensure_shader_resource_view (dmem)) {
if (!gst_d3d11_memory_ensure_shader_resource_view (dmem)) {
GST_ERROR_OBJECT (self, "shader resource view is not available");
gst_buffer_unref (render_buf);

View file

@ -64,9 +64,6 @@ struct _GstD3D11VideoSink
GstBufferPool *fallback_pool;
gboolean can_convert;
/* whether shader resource view is required for direct rendering or not */
gboolean need_srv;
};
struct _GstD3D11VideoSinkClass

View file

@ -530,14 +530,14 @@ gst_d3d11_window_on_resize (GstD3D11Device * device, GstD3D11Window * window)
{
HRESULT hr;
ID3D11Device *d3d11_dev;
ID3D11DeviceContext *d3d11_context;
guint width, height;
D3D11_TEXTURE2D_DESC desc;
DXGI_SWAP_CHAIN_DESC swap_desc;
if (!window->swap_chain)
return;
d3d11_dev = gst_d3d11_device_get_device_handle (device);
d3d11_context = gst_d3d11_device_get_device_context_handle (device);
if (window->backbuffer) {
ID3D11Texture2D_Release (window->backbuffer);
@ -549,79 +549,10 @@ gst_d3d11_window_on_resize (GstD3D11Device * device, GstD3D11Window * window)
window->rtv = NULL;
}
width = window->width;
height = window->height;
if (width != window->surface_width || height != window->surface_height) {
GstVideoRectangle src_rect, dst_rect;
src_rect.x = 0;
src_rect.y = 0;
src_rect.w = width * window->aspect_ratio_n;
src_rect.h = height * window->aspect_ratio_d;
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.w = window->surface_width;
dst_rect.h = window->surface_height;
if (window->converter) {
if (window->force_aspect_ratio) {
src_rect.w = width * window->aspect_ratio_n;
src_rect.h = height * window->aspect_ratio_d;
gst_video_sink_center_rect (src_rect, dst_rect, &window->render_rect,
TRUE);
} else {
window->render_rect = dst_rect;
}
width = window->surface_width;
height = window->surface_height;
} else {
/* NOTE: there can be various way to resize texture, but
* we just copy incoming texture toward resized swap chain buffer in order to
* avoid shader coding.
* To keep aspect ratio, required vertical or horizontal padding area
* will be calculated in here.
*/
gdouble src_ratio, dst_ratio;
gdouble aspect_ratio =
(gdouble) window->aspect_ratio_n / (gdouble) window->aspect_ratio_d;
src_ratio = (gdouble) width / height;
dst_ratio =
(gdouble) window->surface_width / window->surface_height /
aspect_ratio;
src_rect.w = width;
src_rect.h = height;
if (window->force_aspect_ratio) {
if (src_ratio > dst_ratio) {
/* padding top and bottom */
dst_rect.w = width;
dst_rect.h = width / dst_ratio;
} else {
/* padding left and right */
dst_rect.w = height * dst_ratio;
dst_rect.h = height;
}
} else {
dst_rect.w = width;
dst_rect.h = height;
}
gst_video_sink_center_rect (src_rect, dst_rect, &window->render_rect,
TRUE);
width = dst_rect.w;
height = dst_rect.h;
}
}
/* Set zero width and height here. dxgi will decide client area by itself */
IDXGISwapChain_GetDesc (window->swap_chain, &swap_desc);
hr = IDXGISwapChain_ResizeBuffers (window->swap_chain,
0, width, height, DXGI_FORMAT_UNKNOWN, 0);
0, 0, 0, DXGI_FORMAT_UNKNOWN, swap_desc.Flags);
if (!gst_d3d11_result (hr)) {
GST_ERROR_OBJECT (window, "Couldn't resize buffers, hr: 0x%x", (guint) hr);
return;
@ -635,6 +566,42 @@ gst_d3d11_window_on_resize (GstD3D11Device * device, GstD3D11Window * window)
return;
}
ID3D11Texture2D_GetDesc (window->backbuffer, &desc);
window->surface_width = desc.Width;
window->surface_height = desc.Height;
width = window->width;
height = window->height;
{
GstVideoRectangle src_rect, dst_rect;
src_rect.x = 0;
src_rect.y = 0;
src_rect.w = width * window->aspect_ratio_n;
src_rect.h = height * window->aspect_ratio_d;
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.w = window->surface_width;
dst_rect.h = window->surface_height;
if (window->force_aspect_ratio) {
src_rect.w = width * window->aspect_ratio_n;
src_rect.h = height * window->aspect_ratio_d;
gst_video_sink_center_rect (src_rect, dst_rect, &window->render_rect,
TRUE);
} else {
window->render_rect = dst_rect;
}
}
GST_LOG_OBJECT (window,
"New client area %dx%d, render rect x: %d, y: %d, %dx%d",
desc.Width, desc.Height, window->render_rect.x, window->render_rect.y,
window->render_rect.w, window->render_rect.h);
hr = ID3D11Device_CreateRenderTargetView (d3d11_dev,
(ID3D11Resource *) window->backbuffer, NULL, &window->rtv);
if (!gst_d3d11_result (hr)) {
@ -643,7 +610,6 @@ gst_d3d11_window_on_resize (GstD3D11Device * device, GstD3D11Window * window)
return;
}
ID3D11DeviceContext_OMSetRenderTargets (d3d11_context, 1, &window->rtv, NULL);
if (window->cached_buffer) {
FramePresentData present_data = { 0, };
@ -660,16 +626,6 @@ static void
gst_d3d11_window_on_size (GstD3D11Window * self,
HWND hWnd, WPARAM wParam, LPARAM lParam)
{
RECT clientRect = { 0, };
GetClientRect (hWnd, &clientRect);
self->surface_width = clientRect.right - clientRect.left;
self->surface_height = clientRect.bottom - clientRect.top;
GST_LOG_OBJECT (self, "WM_PAINT, surface %ux%u",
self->surface_width, self->surface_height);
gst_d3d11_device_thread_add_full (self->device, G_PRIORITY_HIGH,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_on_resize, self, NULL);
}
@ -1013,8 +969,7 @@ gst_d3d11_window_color_space_from_video_info (GstD3D11Window * self,
gboolean
gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
guint aspect_ratio_n, guint aspect_ratio_d, GstCaps * caps,
gboolean * do_convert, GError ** error)
guint aspect_ratio_n, guint aspect_ratio_d, GstCaps * caps, GError ** error)
{
DXGI_SWAP_CHAIN_DESC desc = { 0, };
GstCaps *render_caps;
@ -1027,7 +982,6 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
g_return_val_if_fail (aspect_ratio_n > 0, FALSE);
g_return_val_if_fail (aspect_ratio_d > 0, FALSE);
g_return_val_if_fail (do_convert != NULL, FALSE);
GST_DEBUG_OBJECT (window, "Prepare window with %dx%d caps %" GST_PTR_FORMAT,
width, height, caps);
@ -1073,19 +1027,16 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
window->info.colorimetry.primaries;
window->render_info.colorimetry.transfer = window->info.colorimetry.transfer;
if (GST_VIDEO_INFO_FORMAT (&window->info) !=
GST_VIDEO_INFO_FORMAT (&window->render_info)) {
window->converter =
gst_d3d11_color_converter_new (window->device, &window->info,
&window->render_info);
window->converter =
gst_d3d11_color_converter_new (window->device, &window->info,
&window->render_info);
if (!window->converter) {
GST_ERROR_OBJECT (window, "Cannot create converter");
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
"Cannot create converter");
if (!window->converter) {
GST_ERROR_OBJECT (window, "Cannot create converter");
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
"Cannot create converter");
return FALSE;
}
return FALSE;
}
#if defined(HAVE_DXGI_1_5_H)
if (!gst_video_content_light_level_from_caps (&window->content_light_level,
@ -1133,8 +1084,12 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
window->surface_height = height;
}
desc.BufferDesc.Width = window->width = window->surface_width;
desc.BufferDesc.Height = window->height = window->surface_height;
window->width = width;
window->height = height;
/* we will get client area at on_resize */
desc.BufferDesc.Width = 0;
desc.BufferDesc.Height = 0;
/* don't care refresh rate */
desc.BufferDesc.RefreshRate.Numerator = 0;
desc.BufferDesc.RefreshRate.Denominator = 1;
@ -1222,8 +1177,6 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
GST_DEBUG_OBJECT (window, "New swap chain 0x%p created", window->swap_chain);
*do_convert = ! !window->converter;
return TRUE;
}
@ -1312,54 +1265,31 @@ _present_on_device_thread (GstD3D11Device * device, FramePresentData * data)
GstD3D11Window *self = data->window;
ID3D11DeviceContext *device_context;
HRESULT hr;
float black[] = { 0.0f, 0.0f, 0.0f, 0.0f };
D3D11_BOX src_box;
device_context = gst_d3d11_device_get_device_context_handle (device);
gst_buffer_replace (&self->cached_buffer, data->buffer);
if (self->cached_buffer) {
if (self->converter) {
ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
gint i, j, k;
RECT rect;
ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
gint i, j, k;
RECT rect;
for (i = 0, j = 0; i < gst_buffer_n_memory (self->cached_buffer); i++) {
GstD3D11Memory *mem =
(GstD3D11Memory *) gst_buffer_peek_memory (self->cached_buffer, i);
for (k = 0; k < mem->num_shader_resource_views; k++) {
srv[j] = mem->shader_resource_view[k];
j++;
}
}
rect.left = self->render_rect.x;
rect.right = self->render_rect.x + self->render_rect.w;
rect.top = self->render_rect.y;
rect.bottom = self->render_rect.y + self->render_rect.h;
gst_d3d11_color_converter_update_rect (self->converter, &rect);
gst_d3d11_color_converter_convert (self->converter, srv, &self->rtv);
} else {
for (i = 0, j = 0; i < gst_buffer_n_memory (self->cached_buffer); i++) {
GstD3D11Memory *mem =
(GstD3D11Memory *) gst_buffer_peek_memory (self->cached_buffer, 0);
self->rect = *data->rect;
src_box.left = self->rect.x;
src_box.right = self->rect.x + self->rect.w;
src_box.top = self->rect.y;
src_box.bottom = self->rect.y + self->rect.h;
src_box.front = 0;
src_box.back = 1;
ID3D11DeviceContext_OMSetRenderTargets (device_context,
1, &self->rtv, NULL);
ID3D11DeviceContext_ClearRenderTargetView (device_context, self->rtv,
black);
ID3D11DeviceContext_CopySubresourceRegion (device_context,
(ID3D11Resource *) self->backbuffer, 0, self->render_rect.x,
self->render_rect.y, 0, (ID3D11Resource *) mem->texture, 0, &src_box);
(GstD3D11Memory *) gst_buffer_peek_memory (self->cached_buffer, i);
for (k = 0; k < mem->num_shader_resource_views; k++) {
srv[j] = mem->shader_resource_view[k];
j++;
}
}
rect.left = self->render_rect.x;
rect.right = self->render_rect.x + self->render_rect.w;
rect.top = self->render_rect.y;
rect.bottom = self->render_rect.y + self->render_rect.h;
gst_d3d11_color_converter_update_rect (self->converter, &rect);
gst_d3d11_color_converter_convert (self->converter, srv, &self->rtv);
}
hr = IDXGISwapChain_Present (self->swap_chain, 0, DXGI_PRESENT_DO_NOT_WAIT);
@ -1401,13 +1331,10 @@ gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer,
g_mutex_unlock (&window->lock);
GST_OBJECT_LOCK (window);
if (rect->w != window->width || rect->h != window->height ||
window->pending_resize) {
window->width = rect->w;
window->height = rect->h;
if (window->pending_resize) {
gst_d3d11_device_thread_add (window->device,
(GstD3D11DeviceThreadFunc) gst_d3d11_window_on_resize, window);
window->pending_resize = FALSE;
}
GST_OBJECT_UNLOCK (window);

View file

@ -138,7 +138,6 @@ gboolean gst_d3d11_window_prepare (GstD3D11Window * window,
guint aspect_ratio_n,
guint aspect_ratio_d,
GstCaps * caps,
gboolean * do_convert,
GError ** error);
GstFlowReturn gst_d3d11_window_render (GstD3D11Window * window,