mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
d3d11videosink: Use single GstD3D11Converter object
GstD3D11Converter supports videoprocessor and texture upload. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2697>
This commit is contained in:
parent
46a3394581
commit
5eeec16502
4 changed files with 306 additions and 925 deletions
|
@ -125,10 +125,6 @@ struct _GstD3D11VideoSink
|
|||
GstVideoRectangle render_rect;
|
||||
gboolean pending_render_rect;
|
||||
|
||||
GstBufferPool *fallback_pool;
|
||||
gboolean have_video_processor;
|
||||
gboolean processor_in_use;
|
||||
|
||||
/* For drawing on user texture */
|
||||
gboolean drawing;
|
||||
GstBuffer *current_buffer;
|
||||
|
@ -596,10 +592,8 @@ gst_d3d11_video_sink_update_window (GstD3D11VideoSink * self, GstCaps * caps)
|
|||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
|
||||
self->have_video_processor = FALSE;
|
||||
if (!gst_d3d11_window_prepare (self->window, GST_VIDEO_SINK_WIDTH (self),
|
||||
GST_VIDEO_SINK_HEIGHT (self), caps, &self->have_video_processor,
|
||||
&error)) {
|
||||
GST_VIDEO_SINK_HEIGHT (self), caps, &error)) {
|
||||
GstMessage *error_msg;
|
||||
|
||||
GST_ERROR_OBJECT (self, "cannot create swapchain");
|
||||
|
@ -611,44 +605,6 @@ gst_d3d11_video_sink_update_window (GstD3D11VideoSink * self, GstCaps * caps)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (self->fallback_pool) {
|
||||
gst_buffer_pool_set_active (self->fallback_pool, FALSE);
|
||||
gst_clear_object (&self->fallback_pool);
|
||||
}
|
||||
|
||||
{
|
||||
GstD3D11AllocationParams *d3d11_params;
|
||||
gint bind_flags = D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
if (self->have_video_processor) {
|
||||
/* To create video processor input view, one of following bind flags
|
||||
* is required
|
||||
* NOTE: Any texture arrays which were created with D3D11_BIND_DECODER flag
|
||||
* cannot be used for shader input.
|
||||
*
|
||||
* D3D11_BIND_DECODER
|
||||
* D3D11_BIND_VIDEO_ENCODER
|
||||
* D3D11_BIND_RENDER_TARGET
|
||||
* D3D11_BIND_UNORDERED_ACCESS_VIEW
|
||||
*/
|
||||
bind_flags |= D3D11_BIND_RENDER_TARGET;
|
||||
}
|
||||
|
||||
d3d11_params = gst_d3d11_allocation_params_new (self->device,
|
||||
&self->info, GST_D3D11_ALLOCATION_FLAG_DEFAULT, bind_flags, 0);
|
||||
|
||||
self->fallback_pool = gst_d3d11_buffer_pool_new_with_options (self->device,
|
||||
caps, d3d11_params, 2, 0);
|
||||
gst_d3d11_allocation_params_free (d3d11_params);
|
||||
}
|
||||
|
||||
if (!self->fallback_pool) {
|
||||
GST_ERROR_OBJECT (self, "Failed to configure fallback pool");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
self->processor_in_use = FALSE;
|
||||
|
||||
if (self->title) {
|
||||
gst_d3d11_window_set_title (self->window, self->title);
|
||||
g_clear_pointer (&self->title, g_free);
|
||||
|
@ -838,12 +794,6 @@ gst_d3d11_video_sink_stop (GstBaseSink * sink)
|
|||
|
||||
GST_DEBUG_OBJECT (self, "Stop");
|
||||
|
||||
if (self->fallback_pool) {
|
||||
gst_buffer_pool_set_active (self->fallback_pool, FALSE);
|
||||
gst_object_unref (self->fallback_pool);
|
||||
self->fallback_pool = NULL;
|
||||
}
|
||||
|
||||
if (self->window)
|
||||
gst_d3d11_window_unprepare (self->window);
|
||||
|
||||
|
@ -1050,108 +1000,6 @@ gst_d3d11_video_sink_event (GstBaseSink * sink, GstEvent * event)
|
|||
return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_video_sink_upload_frame (GstD3D11VideoSink * self, GstBuffer * inbuf,
|
||||
GstBuffer * outbuf)
|
||||
{
|
||||
GstVideoFrame in_frame, out_frame;
|
||||
gboolean ret;
|
||||
|
||||
GST_LOG_OBJECT (self, "Copy to fallback buffer");
|
||||
|
||||
if (!gst_video_frame_map (&in_frame, &self->info, inbuf,
|
||||
(GstMapFlags) (GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)))
|
||||
goto invalid_buffer;
|
||||
|
||||
if (!gst_video_frame_map (&out_frame, &self->info, outbuf,
|
||||
(GstMapFlags) (GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))) {
|
||||
gst_video_frame_unmap (&in_frame);
|
||||
goto invalid_buffer;
|
||||
}
|
||||
|
||||
ret = gst_video_frame_copy (&out_frame, &in_frame);
|
||||
|
||||
gst_video_frame_unmap (&in_frame);
|
||||
gst_video_frame_unmap (&out_frame);
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
invalid_buffer:
|
||||
{
|
||||
GST_ELEMENT_WARNING (self, CORE, NOT_IMPLEMENTED, (NULL),
|
||||
("invalid video buffer received"));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_video_sink_copy_d3d11_to_d3d11 (GstD3D11VideoSink * self,
|
||||
GstBuffer * inbuf, GstBuffer * outbuf)
|
||||
{
|
||||
GST_LOG_OBJECT (self, "Copy to fallback buffer using device memory copy");
|
||||
|
||||
return gst_d3d11_buffer_copy_into (outbuf, inbuf, &self->info);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_video_sink_get_fallback_buffer (GstD3D11VideoSink * self,
|
||||
GstBuffer * inbuf, GstBuffer ** fallback_buf, gboolean device_copy)
|
||||
{
|
||||
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) ||
|
||||
gst_buffer_pool_acquire_buffer (self->fallback_pool, &outbuf,
|
||||
NULL) != GST_FLOW_OK) {
|
||||
GST_ERROR_OBJECT (self, "fallback pool is unavailable");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Ensure SRV */
|
||||
if (!gst_d3d11_buffer_get_shader_resource_view (outbuf, view)) {
|
||||
GST_ERROR_OBJECT (self, "fallback SRV is unavailable");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (device_copy) {
|
||||
if (!gst_d3d11_video_sink_copy_d3d11_to_d3d11 (self, inbuf, outbuf)) {
|
||||
GST_ERROR_OBJECT (self, "cannot copy frame");
|
||||
goto error;
|
||||
}
|
||||
} else if (!gst_d3d11_video_sink_upload_frame (self, inbuf, outbuf)) {
|
||||
GST_ERROR_OBJECT (self, "cannot upload frame");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Copy overlaycomposition meta if any */
|
||||
compo_meta = gst_buffer_get_video_overlay_composition_meta (inbuf);
|
||||
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;
|
||||
|
||||
error:
|
||||
gst_buffer_unref (outbuf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_video_sink_check_device_update (GstD3D11VideoSink * self,
|
||||
GstBuffer * buf)
|
||||
|
@ -1199,10 +1047,6 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
|
|||
{
|
||||
GstD3D11VideoSink *self = GST_D3D11_VIDEO_SINK (sink);
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstBuffer *fallback_buf = NULL;
|
||||
ID3D11Device *device_handle =
|
||||
gst_d3d11_device_get_device_handle (self->device);
|
||||
ID3D11ShaderResourceView *view[GST_VIDEO_MAX_PLANES];
|
||||
|
||||
gst_d3d11_video_sink_check_device_update (self, buf);
|
||||
|
||||
|
@ -1221,54 +1065,11 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
|
|||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
|
||||
if (!gst_d3d11_buffer_can_access_device (buf, device_handle)) {
|
||||
GST_LOG_OBJECT (self, "Need fallback buffer");
|
||||
|
||||
if (!gst_d3d11_video_sink_get_fallback_buffer (self, buf, &fallback_buf,
|
||||
FALSE)) {
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
} else {
|
||||
gboolean direct_rendering = FALSE;
|
||||
|
||||
/* Check if we can use video processor for conversion */
|
||||
if (gst_buffer_n_memory (buf) == 1 && self->have_video_processor) {
|
||||
GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buf, 0);
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
|
||||
gst_d3d11_memory_get_texture_desc (mem, &desc);
|
||||
if ((desc.BindFlags & D3D11_BIND_DECODER) == D3D11_BIND_DECODER) {
|
||||
GST_TRACE_OBJECT (self,
|
||||
"Got VideoProcessor compatible texture, do direct rendering");
|
||||
direct_rendering = TRUE;
|
||||
self->processor_in_use = TRUE;
|
||||
} else if (self->processor_in_use &&
|
||||
(desc.BindFlags & D3D11_BIND_RENDER_TARGET) ==
|
||||
D3D11_BIND_RENDER_TARGET) {
|
||||
direct_rendering = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Or, SRV should be available */
|
||||
if (!direct_rendering) {
|
||||
if (gst_d3d11_buffer_get_shader_resource_view (buf, view)) {
|
||||
GST_TRACE_OBJECT (self, "SRV is available, do direct rendering");
|
||||
direct_rendering = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!direct_rendering &&
|
||||
!gst_d3d11_video_sink_get_fallback_buffer (self, buf, &fallback_buf,
|
||||
TRUE)) {
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
gst_d3d11_window_show (self->window);
|
||||
|
||||
if (self->draw_on_shared_texture) {
|
||||
g_rec_mutex_lock (&self->draw_lock);
|
||||
self->current_buffer = fallback_buf ? fallback_buf : buf;
|
||||
self->current_buffer = buf;
|
||||
self->drawing = TRUE;
|
||||
|
||||
GST_LOG_OBJECT (self, "Begin drawing");
|
||||
|
@ -1279,15 +1080,12 @@ gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
|
|||
|
||||
GST_LOG_OBJECT (self, "End drawing");
|
||||
self->drawing = FALSE;
|
||||
self->current_buffer = NULL;
|
||||
self->current_buffer = nullptr;
|
||||
g_rec_mutex_unlock (&self->draw_lock);
|
||||
} else {
|
||||
ret = gst_d3d11_window_render (self->window,
|
||||
fallback_buf ? fallback_buf : buf);
|
||||
ret = gst_d3d11_window_render (self->window, buf);
|
||||
}
|
||||
|
||||
gst_clear_buffer (&fallback_buf);
|
||||
|
||||
if (ret == GST_D3D11_WINDOW_FLOW_CLOSED) {
|
||||
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
||||
("Output window was closed"), (NULL));
|
||||
|
|
|
@ -103,13 +103,11 @@ static void gst_d3d11_window_get_property (GObject * object, guint prop_id,
|
|||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_d3d11_window_dispose (GObject * object);
|
||||
static GstFlowReturn gst_d3d111_window_present (GstD3D11Window * self,
|
||||
GstBuffer * buffer, ID3D11VideoProcessorOutputView * pov,
|
||||
ID3D11RenderTargetView * rtv);
|
||||
GstBuffer * buffer, GstBuffer * render_target);
|
||||
static void gst_d3d11_window_on_resize_default (GstD3D11Window * window,
|
||||
guint width, guint height);
|
||||
static gboolean gst_d3d11_window_prepare_default (GstD3D11Window * window,
|
||||
guint display_width, guint display_height, GstCaps * caps,
|
||||
gboolean * video_processor_available, GError ** error);
|
||||
guint display_width, guint display_height, GstCaps * caps, GError ** error);
|
||||
|
||||
static void
|
||||
gst_d3d11_window_class_init (GstD3D11WindowClass * klass)
|
||||
|
@ -251,132 +249,116 @@ gst_d3d11_window_get_property (GObject * object, guint prop_id,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_release_resources (GstD3D11Device * device,
|
||||
GstD3D11Window * window)
|
||||
{
|
||||
GST_D3D11_CLEAR_COM (window->rtv);
|
||||
GST_D3D11_CLEAR_COM (window->pov);
|
||||
GST_D3D11_CLEAR_COM (window->swap_chain);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_dispose (GObject * object)
|
||||
{
|
||||
GstD3D11Window *self = GST_D3D11_WINDOW (object);
|
||||
|
||||
if (self->device)
|
||||
gst_d3d11_window_release_resources (self->device, self);
|
||||
gst_clear_buffer (&self->backbuffer);
|
||||
GST_D3D11_CLEAR_COM (self->swap_chain);
|
||||
|
||||
g_clear_pointer (&self->processor, gst_d3d11_video_processor_free);
|
||||
gst_clear_object (&self->compositor);
|
||||
gst_clear_object (&self->converter);
|
||||
|
||||
gst_clear_buffer (&self->cached_buffer);
|
||||
gst_clear_object (&self->device);
|
||||
gst_clear_object (&self->allocator);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_on_resize_default (GstD3D11Window * window, guint width,
|
||||
gst_d3d11_window_on_resize_default (GstD3D11Window * self, guint width,
|
||||
guint height)
|
||||
{
|
||||
GstD3D11Device *device = self->device;
|
||||
HRESULT hr;
|
||||
ID3D11Device *device_handle;
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
DXGI_SWAP_CHAIN_DESC swap_desc;
|
||||
ID3D11Texture2D *backbuffer = NULL;
|
||||
ComPtr < ID3D11Texture2D > backbuffer;
|
||||
GstVideoRectangle src_rect, dst_rect, rst_rect;
|
||||
IDXGISwapChain *swap_chain;
|
||||
GstMemory *mem;
|
||||
GstD3D11Memory *dmem;
|
||||
ID3D11RenderTargetView *rtv;
|
||||
|
||||
gst_d3d11_device_lock (window->device);
|
||||
if (!window->swap_chain)
|
||||
gst_d3d11_device_lock (device);
|
||||
|
||||
gst_clear_buffer (&self->backbuffer);
|
||||
if (!self->swap_chain)
|
||||
goto done;
|
||||
|
||||
device_handle = gst_d3d11_device_get_device_handle (window->device);
|
||||
swap_chain = window->swap_chain;
|
||||
|
||||
GST_D3D11_CLEAR_COM (window->rtv);
|
||||
GST_D3D11_CLEAR_COM (window->pov);
|
||||
|
||||
swap_chain = self->swap_chain;
|
||||
swap_chain->GetDesc (&swap_desc);
|
||||
hr = swap_chain->ResizeBuffers (0, width, height, window->dxgi_format,
|
||||
hr = swap_chain->ResizeBuffers (0, width, height, self->dxgi_format,
|
||||
swap_desc.Flags);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_ERROR_OBJECT (window, "Couldn't resize buffers, hr: 0x%x", (guint) hr);
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't resize buffers, hr: 0x%x", (guint) hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
hr = swap_chain->GetBuffer (0, IID_PPV_ARGS (&backbuffer));
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_ERROR_OBJECT (window,
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"Cannot get backbuffer from swapchain, hr: 0x%x", (guint) hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
backbuffer->GetDesc (&desc);
|
||||
window->surface_width = desc.Width;
|
||||
window->surface_height = desc.Height;
|
||||
|
||||
{
|
||||
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.x = 0;
|
||||
src_rect.y = 0;
|
||||
src_rect.w = GST_VIDEO_INFO_WIDTH (&window->render_info);
|
||||
src_rect.h = GST_VIDEO_INFO_HEIGHT (&window->render_info);
|
||||
|
||||
gst_video_sink_center_rect (src_rect, dst_rect, &rst_rect, TRUE);
|
||||
} else {
|
||||
rst_rect = dst_rect;
|
||||
}
|
||||
}
|
||||
|
||||
window->render_rect.left = rst_rect.x;
|
||||
window->render_rect.top = rst_rect.y;
|
||||
window->render_rect.right = rst_rect.x + rst_rect.w;
|
||||
window->render_rect.bottom = rst_rect.y + rst_rect.h;
|
||||
|
||||
GST_LOG_OBJECT (window,
|
||||
"New client area %dx%d, render rect x: %d, y: %d, %dx%d",
|
||||
desc.Width, desc.Height, rst_rect.x, rst_rect.y, rst_rect.w, rst_rect.h);
|
||||
|
||||
hr = device_handle->CreateRenderTargetView (backbuffer, NULL, &window->rtv);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_ERROR_OBJECT (window, "Cannot create render target view, hr: 0x%x",
|
||||
(guint) hr);
|
||||
|
||||
mem = gst_d3d11_allocator_alloc_wrapped_native_size (self->allocator,
|
||||
self->device, backbuffer.Get (), nullptr, nullptr);
|
||||
if (!mem) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't allocate wrapped memory");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (window->processor) {
|
||||
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC pov_desc;
|
||||
|
||||
pov_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
|
||||
pov_desc.Texture2D.MipSlice = 0;
|
||||
|
||||
if (!gst_d3d11_video_processor_create_output_view (window->processor,
|
||||
&pov_desc, backbuffer, &window->pov))
|
||||
goto done;
|
||||
dmem = GST_D3D11_MEMORY_CAST (mem);
|
||||
rtv = gst_d3d11_memory_get_render_target_view (dmem, 0);
|
||||
if (!rtv) {
|
||||
GST_ERROR_OBJECT (self, "RTV is unavailable");
|
||||
gst_memory_unref (mem);
|
||||
goto done;
|
||||
}
|
||||
|
||||
window->first_present = TRUE;
|
||||
self->backbuffer = gst_buffer_new ();
|
||||
gst_buffer_append_memory (self->backbuffer, mem);
|
||||
|
||||
backbuffer->GetDesc (&desc);
|
||||
self->surface_width = desc.Width;
|
||||
self->surface_height = desc.Height;
|
||||
|
||||
dst_rect.x = 0;
|
||||
dst_rect.y = 0;
|
||||
dst_rect.w = self->surface_width;
|
||||
dst_rect.h = self->surface_height;
|
||||
|
||||
if (self->force_aspect_ratio) {
|
||||
src_rect.x = 0;
|
||||
src_rect.y = 0;
|
||||
src_rect.w = GST_VIDEO_INFO_WIDTH (&self->render_info);
|
||||
src_rect.h = GST_VIDEO_INFO_HEIGHT (&self->render_info);
|
||||
|
||||
gst_video_sink_center_rect (src_rect, dst_rect, &rst_rect, TRUE);
|
||||
} else {
|
||||
rst_rect = dst_rect;
|
||||
}
|
||||
|
||||
self->render_rect.left = rst_rect.x;
|
||||
self->render_rect.top = rst_rect.y;
|
||||
self->render_rect.right = rst_rect.x + rst_rect.w;
|
||||
self->render_rect.bottom = rst_rect.y + rst_rect.h;
|
||||
|
||||
GST_LOG_OBJECT (self,
|
||||
"New client area %dx%d, render rect x: %d, y: %d, %dx%d",
|
||||
desc.Width, desc.Height, rst_rect.x, rst_rect.y, rst_rect.w, rst_rect.h);
|
||||
|
||||
self->first_present = TRUE;
|
||||
|
||||
/* redraw the last scene if cached buffer exits */
|
||||
if (window->cached_buffer) {
|
||||
gst_d3d111_window_present (window, window->cached_buffer,
|
||||
window->pov, window->rtv);
|
||||
}
|
||||
if (self->cached_buffer)
|
||||
gst_d3d111_window_present (self, self->cached_buffer, self->backbuffer);
|
||||
|
||||
done:
|
||||
GST_D3D11_CLEAR_COM (backbuffer);
|
||||
|
||||
gst_d3d11_device_unlock (window->device);
|
||||
gst_d3d11_device_unlock (device);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -413,8 +395,7 @@ typedef struct
|
|||
|
||||
gboolean
|
||||
gst_d3d11_window_prepare (GstD3D11Window * window, guint display_width,
|
||||
guint display_height, GstCaps * caps, gboolean * video_processor_available,
|
||||
GError ** error)
|
||||
guint display_height, GstCaps * caps, GError ** error)
|
||||
{
|
||||
GstD3D11WindowClass *klass;
|
||||
|
||||
|
@ -426,19 +407,17 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint display_width,
|
|||
GST_DEBUG_OBJECT (window, "Prepare window, display resolution %dx%d, caps %"
|
||||
GST_PTR_FORMAT, display_width, display_height, caps);
|
||||
|
||||
return klass->prepare (window, display_width, display_height, caps,
|
||||
video_processor_available, error);
|
||||
return klass->prepare (window, display_width, display_height, caps, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
||||
guint display_height, GstCaps * caps, gboolean * video_processor_available,
|
||||
GError ** error)
|
||||
guint display_height, GstCaps * caps, GError ** error)
|
||||
{
|
||||
GstD3D11Device *device = window->device;
|
||||
GstD3D11WindowClass *klass;
|
||||
guint swapchain_flags = 0;
|
||||
ID3D11Device *device_handle;
|
||||
guint i;
|
||||
guint num_supported_format = 0;
|
||||
HRESULT hr;
|
||||
UINT display_flags =
|
||||
|
@ -452,28 +431,41 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
const GstD3D11WindowDisplayFormat *chosen_format = NULL;
|
||||
GstDxgiColorSpace swapchain_colorspace;
|
||||
gboolean found_swapchain_colorspace = FALSE;
|
||||
gboolean have_hdr10 = FALSE;
|
||||
gboolean hdr10_aware = FALSE;
|
||||
gboolean have_hdr10_meta = FALSE;
|
||||
DXGI_COLOR_SPACE_TYPE native_colorspace_type =
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
DXGI_HDR_METADATA_HDR10 hdr10_metadata = { 0, };
|
||||
GstDxgiColorSpace in_dxgi_colorspace;
|
||||
GstD3D11ConverterMethod method = GST_D3D11_CONVERTER_METHOD_SHADER;
|
||||
ComPtr < IDXGIFactory5 > factory5;
|
||||
IDXGIFactory1 *factory_handle;
|
||||
BOOL allow_tearing = FALSE;
|
||||
GstVideoMasteringDisplayInfo mdcv;
|
||||
GstVideoContentLightLevel cll;
|
||||
ComPtr < IDXGISwapChain3 > swapchain3;
|
||||
GstStructure *s;
|
||||
const gchar *cll_str = nullptr;
|
||||
const gchar *mdcv_str = nullptr;
|
||||
|
||||
if (!window->allocator) {
|
||||
window->allocator =
|
||||
(GstD3D11Allocator *) gst_allocator_find (GST_D3D11_MEMORY_NAME);
|
||||
if (!window->allocator) {
|
||||
GST_ERROR_OBJECT (window, "Allocator is unavailable");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 1: Clear old resources and objects */
|
||||
gst_clear_buffer (&window->cached_buffer);
|
||||
g_clear_pointer (&window->processor, gst_d3d11_video_processor_free);
|
||||
gst_clear_object (&window->compositor);
|
||||
gst_clear_object (&window->converter);
|
||||
|
||||
window->processor_in_use = FALSE;
|
||||
|
||||
/* Step 2: Decide display color format
|
||||
* If upstream format is 10bits, try DXGI_FORMAT_R10G10B10A2_UNORM first
|
||||
* Otherwise, use DXGI_FORMAT_B8G8R8A8_UNORM or DXGI_FORMAT_B8G8R8A8_UNORM
|
||||
*/
|
||||
gst_video_info_from_caps (&window->info, caps);
|
||||
device_handle = gst_d3d11_device_get_device_handle (window->device);
|
||||
for (i = 0; i < G_N_ELEMENTS (formats); i++) {
|
||||
device_handle = gst_d3d11_device_get_device_handle (device);
|
||||
for (guint i = 0; i < G_N_ELEMENTS (formats); i++) {
|
||||
hr = device_handle->CheckFormatSupport (formats[i].dxgi_format,
|
||||
&supported_flags);
|
||||
if (SUCCEEDED (hr) && (supported_flags & display_flags) == display_flags) {
|
||||
|
@ -492,7 +484,7 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (&window->info); i++) {
|
||||
for (guint i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (&window->info); i++) {
|
||||
if (GST_VIDEO_INFO_COMP_DEPTH (&window->info, i) > 8) {
|
||||
if (formats[2].supported) {
|
||||
chosen_format = &formats[2];
|
||||
|
@ -503,7 +495,7 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
|
||||
if (!chosen_format) {
|
||||
/* prefer native format over conversion */
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (guint i = 0; i < 2; i++) {
|
||||
if (formats[i].supported &&
|
||||
formats[i].gst_format == GST_VIDEO_INFO_FORMAT (&window->info)) {
|
||||
chosen_format = &formats[i];
|
||||
|
@ -513,7 +505,7 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
|
||||
/* choose any color space then */
|
||||
if (!chosen_format) {
|
||||
for (i = 0; i < G_N_ELEMENTS (formats); i++) {
|
||||
for (guint i = 0; i < G_N_ELEMENTS (formats); i++) {
|
||||
if (formats[i].supported) {
|
||||
chosen_format = &formats[i];
|
||||
break;
|
||||
|
@ -522,7 +514,7 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
}
|
||||
}
|
||||
|
||||
g_assert (chosen_format != NULL);
|
||||
g_assert (chosen_format != nullptr);
|
||||
|
||||
GST_DEBUG_OBJECT (window, "chosen render format %s (DXGI_FORMAT %d)",
|
||||
gst_video_format_to_string (chosen_format->gst_format),
|
||||
|
@ -532,28 +524,17 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
* (or reuse old swapchain if the format is not changed) */
|
||||
window->allow_tearing = FALSE;
|
||||
|
||||
{
|
||||
ComPtr < IDXGIFactory5 > factory5;
|
||||
IDXGIFactory1 *factory_handle;
|
||||
BOOL allow_tearing = FALSE;
|
||||
|
||||
factory_handle = gst_d3d11_device_get_dxgi_factory_handle (window->device);
|
||||
hr = factory_handle->QueryInterface (IID_PPV_ARGS (&factory5));
|
||||
if (SUCCEEDED (hr)) {
|
||||
hr = factory5->CheckFeatureSupport (DXGI_FEATURE_PRESENT_ALLOW_TEARING,
|
||||
(void *) &allow_tearing, sizeof (allow_tearing));
|
||||
}
|
||||
|
||||
if (SUCCEEDED (hr) && allow_tearing)
|
||||
window->allow_tearing = allow_tearing;
|
||||
factory_handle = gst_d3d11_device_get_dxgi_factory_handle (device);
|
||||
hr = factory_handle->QueryInterface (IID_PPV_ARGS (&factory5));
|
||||
if (SUCCEEDED (hr)) {
|
||||
hr = factory5->CheckFeatureSupport (DXGI_FEATURE_PRESENT_ALLOW_TEARING,
|
||||
(void *) &allow_tearing, sizeof (allow_tearing));
|
||||
}
|
||||
|
||||
if (window->allow_tearing) {
|
||||
GST_DEBUG_OBJECT (window, "device supports tearing");
|
||||
swapchain_flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||
}
|
||||
if (SUCCEEDED (hr) && allow_tearing)
|
||||
window->allow_tearing = allow_tearing;
|
||||
|
||||
gst_d3d11_device_lock (window->device);
|
||||
gst_d3d11_device_lock (device);
|
||||
window->dxgi_format = chosen_format->dxgi_format;
|
||||
|
||||
klass = GST_D3D11_WINDOW_GET_CLASS (window);
|
||||
|
@ -580,35 +561,6 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
|
||||
window->prev_input_rect = window->input_rect;
|
||||
|
||||
/* Step 4: Decide render color space and set it on converter/processor */
|
||||
{
|
||||
GstVideoMasteringDisplayInfo minfo;
|
||||
GstVideoContentLightLevel cll;
|
||||
|
||||
if (gst_video_mastering_display_info_from_caps (&minfo, caps) &&
|
||||
gst_video_content_light_level_from_caps (&cll, caps)) {
|
||||
ComPtr < IDXGISwapChain4 > swapchain4;
|
||||
HRESULT hr;
|
||||
|
||||
hr = window->swap_chain->QueryInterface (IID_PPV_ARGS (&swapchain4));
|
||||
if (gst_d3d11_result (hr, window->device)) {
|
||||
GST_DEBUG_OBJECT (window, "Have HDR metadata, set to DXGI swapchain");
|
||||
|
||||
gst_d3d11_hdr_meta_data_to_dxgi (&minfo, &cll, &hdr10_metadata);
|
||||
|
||||
hr = swapchain4->SetHDRMetaData (DXGI_HDR_METADATA_TYPE_HDR10,
|
||||
sizeof (DXGI_HDR_METADATA_HDR10), &hdr10_metadata);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_WARNING_OBJECT (window, "Couldn't set HDR metadata, hr 0x%x",
|
||||
(guint) hr);
|
||||
} else {
|
||||
have_hdr10 = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 5: Choose display color space */
|
||||
gst_video_info_set_format (&window->render_info,
|
||||
chosen_format->gst_format, display_width, display_height);
|
||||
|
||||
|
@ -621,36 +573,63 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
* target display color space type */
|
||||
window->render_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
|
||||
|
||||
{
|
||||
ComPtr < IDXGISwapChain3 > swapchain3;
|
||||
HRESULT hr;
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
mdcv_str = gst_structure_get_string (s, "mastering-display-info");
|
||||
cll_str = gst_structure_get_string (s, "content-light-level");
|
||||
if (mdcv_str && cll_str &&
|
||||
gst_video_mastering_display_info_from_string (&mdcv, mdcv_str) &&
|
||||
gst_video_content_light_level_from_string (&cll, cll_str)) {
|
||||
have_hdr10_meta = TRUE;
|
||||
}
|
||||
|
||||
hr = window->swap_chain->QueryInterface (IID_PPV_ARGS (&swapchain3));
|
||||
hr = window->swap_chain->QueryInterface (IID_PPV_ARGS (&swapchain3));
|
||||
if (gst_d3d11_result (hr, device)) {
|
||||
found_swapchain_colorspace =
|
||||
gst_d3d11_find_swap_chain_color_space (&window->render_info,
|
||||
swapchain3.Get (), &swapchain_colorspace);
|
||||
if (found_swapchain_colorspace) {
|
||||
native_colorspace_type =
|
||||
(DXGI_COLOR_SPACE_TYPE) swapchain_colorspace.dxgi_color_space_type;
|
||||
hr = swapchain3->SetColorSpace1 (native_colorspace_type);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_WARNING_OBJECT (window, "Failed to set colorspace %d, hr: 0x%x",
|
||||
native_colorspace_type, (guint) hr);
|
||||
found_swapchain_colorspace = FALSE;
|
||||
native_colorspace_type = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
} else {
|
||||
ComPtr < IDXGISwapChain4 > swapchain4;
|
||||
|
||||
if (gst_d3d11_result (hr, window->device)) {
|
||||
found_swapchain_colorspace =
|
||||
gst_d3d11_find_swap_chain_color_space (&window->render_info,
|
||||
swapchain3.Get (), &swapchain_colorspace);
|
||||
if (found_swapchain_colorspace) {
|
||||
native_colorspace_type =
|
||||
(DXGI_COLOR_SPACE_TYPE) swapchain_colorspace.dxgi_color_space_type;
|
||||
hr = swapchain3->SetColorSpace1 (native_colorspace_type);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_WARNING_OBJECT (window, "Failed to set colorspace %d, hr: 0x%x",
|
||||
native_colorspace_type, (guint) hr);
|
||||
found_swapchain_colorspace = FALSE;
|
||||
native_colorspace_type = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (window,
|
||||
"Set colorspace %d", native_colorspace_type);
|
||||
GST_DEBUG_OBJECT (window, "Set colorspace %d", native_colorspace_type);
|
||||
|
||||
/* update with selected display color space */
|
||||
window->render_info.colorimetry.primaries =
|
||||
swapchain_colorspace.primaries;
|
||||
window->render_info.colorimetry.transfer =
|
||||
swapchain_colorspace.transfer;
|
||||
window->render_info.colorimetry.range = swapchain_colorspace.range;
|
||||
window->render_info.colorimetry.matrix = swapchain_colorspace.matrix;
|
||||
/* update with selected display color space */
|
||||
window->render_info.colorimetry.primaries =
|
||||
swapchain_colorspace.primaries;
|
||||
window->render_info.colorimetry.transfer =
|
||||
swapchain_colorspace.transfer;
|
||||
window->render_info.colorimetry.range = swapchain_colorspace.range;
|
||||
window->render_info.colorimetry.matrix = swapchain_colorspace.matrix;
|
||||
|
||||
/* DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 = 12, undefined in old
|
||||
* mingw header */
|
||||
if (native_colorspace_type == 12 && have_hdr10_meta) {
|
||||
hr = swapchain3.As (&swapchain4);
|
||||
if (gst_d3d11_result (hr, device)) {
|
||||
DXGI_HDR_METADATA_HDR10 hdr10_metadata = { 0, };
|
||||
|
||||
GST_DEBUG_OBJECT (window,
|
||||
"Have HDR metadata, set to DXGI swapchain");
|
||||
|
||||
gst_d3d11_hdr_meta_data_to_dxgi (&mdcv, &cll, &hdr10_metadata);
|
||||
|
||||
hr = swapchain4->SetHDRMetaData (DXGI_HDR_METADATA_TYPE_HDR10,
|
||||
sizeof (DXGI_HDR_METADATA_HDR10), &hdr10_metadata);
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_WARNING_OBJECT (window,
|
||||
"Couldn't set HDR metadata, hr 0x%x", (guint) hr);
|
||||
} else {
|
||||
hdr10_aware = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -664,66 +643,10 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
window->render_info.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
|
||||
window->render_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
|
||||
window->render_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
|
||||
} else if (gst_d3d11_video_info_to_dxgi_color_space (&window->info,
|
||||
&in_dxgi_colorspace)) {
|
||||
GstD3D11Format in_format;
|
||||
gboolean hardware = FALSE;
|
||||
GstD3D11VideoProcessor *processor = NULL;
|
||||
DXGI_FORMAT in_dxgi_format;
|
||||
|
||||
gst_d3d11_device_get_format (window->device,
|
||||
GST_VIDEO_INFO_FORMAT (&window->info), &in_format);
|
||||
in_dxgi_format = in_format.dxgi_format;
|
||||
|
||||
if (in_format.dxgi_format != DXGI_FORMAT_UNKNOWN) {
|
||||
g_object_get (window->device, "hardware", &hardware, NULL);
|
||||
}
|
||||
|
||||
if (hardware) {
|
||||
processor =
|
||||
gst_d3d11_video_processor_new (window->device,
|
||||
GST_VIDEO_INFO_WIDTH (&window->info),
|
||||
GST_VIDEO_INFO_HEIGHT (&window->info), display_width, display_height);
|
||||
}
|
||||
|
||||
if (processor) {
|
||||
DXGI_FORMAT out_dxgi_format = chosen_format->dxgi_format;
|
||||
DXGI_COLOR_SPACE_TYPE in_dxgi_color_space =
|
||||
(DXGI_COLOR_SPACE_TYPE) in_dxgi_colorspace.dxgi_color_space_type;
|
||||
DXGI_COLOR_SPACE_TYPE out_dxgi_color_space = native_colorspace_type;
|
||||
|
||||
if (!gst_d3d11_video_processor_check_format_conversion (processor,
|
||||
in_dxgi_format, in_dxgi_color_space, out_dxgi_format,
|
||||
out_dxgi_color_space)) {
|
||||
GST_DEBUG_OBJECT (window, "Conversion is not supported by device");
|
||||
gst_d3d11_video_processor_free (processor);
|
||||
processor = NULL;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (window, "video processor supports conversion");
|
||||
gst_d3d11_video_processor_set_input_dxgi_color_space (processor,
|
||||
in_dxgi_color_space);
|
||||
gst_d3d11_video_processor_set_output_dxgi_color_space (processor,
|
||||
out_dxgi_color_space);
|
||||
|
||||
if (have_hdr10) {
|
||||
GST_DEBUG_OBJECT (window, "Set HDR metadata on video processor");
|
||||
gst_d3d11_video_processor_set_input_hdr10_metadata (processor,
|
||||
&hdr10_metadata);
|
||||
gst_d3d11_video_processor_set_output_hdr10_metadata (processor,
|
||||
&hdr10_metadata);
|
||||
}
|
||||
}
|
||||
|
||||
window->processor = processor;
|
||||
}
|
||||
}
|
||||
|
||||
*video_processor_available = !!window->processor;
|
||||
|
||||
/* configure shader even if video processor is available for fallback */
|
||||
window->converter =
|
||||
gst_d3d11_converter_new (window->device, &window->info,
|
||||
&window->render_info, &method);
|
||||
window->converter = gst_d3d11_converter_new (device,
|
||||
&window->info, &window->render_info, nullptr);
|
||||
|
||||
if (!window->converter) {
|
||||
GST_ERROR_OBJECT (window, "Cannot create converter");
|
||||
|
@ -732,6 +655,15 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (have_hdr10_meta) {
|
||||
g_object_set (window->converter, "src-mastering-display-info", mdcv_str,
|
||||
"src-content-light-level", cll_str, nullptr);
|
||||
if (hdr10_aware) {
|
||||
g_object_set (window->converter, "dest-mastering-display-info", mdcv_str,
|
||||
"dest-content-light-level", cll_str, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
window->compositor =
|
||||
gst_d3d11_overlay_compositor_new (window->device, &window->render_info);
|
||||
if (!window->compositor) {
|
||||
|
@ -799,225 +731,112 @@ gst_d3d11_window_set_title (GstD3D11Window * window, const gchar * title)
|
|||
klass->set_title (window, title);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_buffer_ensure_processor_input (GstD3D11Window * self,
|
||||
GstBuffer * buffer, ID3D11VideoProcessorInputView ** in_view)
|
||||
{
|
||||
GstD3D11Memory *mem;
|
||||
ID3D11VideoProcessorInputView *piv;
|
||||
|
||||
if (!self->processor)
|
||||
return FALSE;
|
||||
|
||||
if (gst_buffer_n_memory (buffer) != 1)
|
||||
return FALSE;
|
||||
|
||||
mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
|
||||
piv = gst_d3d11_video_processor_get_input_view (self->processor, mem);
|
||||
if (!piv) {
|
||||
GST_LOG_OBJECT (self, "Failed to get processor input view");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*in_view = piv;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_do_processor (GstD3D11Window * self,
|
||||
ID3D11VideoProcessorInputView * piv, ID3D11VideoProcessorOutputView * pov,
|
||||
RECT * input_rect)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
ret = gst_d3d11_video_processor_render_unlocked (self->processor,
|
||||
input_rect, piv, &self->render_rect, pov);
|
||||
if (!ret) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't render to backbuffer using processor");
|
||||
} else {
|
||||
GST_TRACE_OBJECT (self, "Rendered using processor");
|
||||
self->processor_in_use = TRUE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_do_convert (GstD3D11Window * self,
|
||||
ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],
|
||||
ID3D11RenderTargetView * rtv, RECT * input_rect)
|
||||
{
|
||||
RECT *prev = &self->prev_input_rect;
|
||||
|
||||
if (input_rect->left != prev->left || input_rect->top != prev->top ||
|
||||
input_rect->right != prev->right || input_rect->bottom != prev->bottom) {
|
||||
g_object_set (self->converter, "src-x", (gint) input_rect->left,
|
||||
"src-y", (gint) input_rect->top,
|
||||
"src-width", (gint) (input_rect->right - input_rect->left),
|
||||
"src-height", (gint) (input_rect->bottom - input_rect->top), nullptr);
|
||||
|
||||
*prev = *input_rect;
|
||||
}
|
||||
|
||||
if (!gst_d3d11_converter_convert_unlocked (self->converter, srv, &rtv)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't render to backbuffer using converter");
|
||||
return FALSE;
|
||||
} else {
|
||||
GST_TRACE_OBJECT (self, "Rendered using converter");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer,
|
||||
ID3D11VideoProcessorOutputView * pov, ID3D11RenderTargetView * rtv)
|
||||
GstBuffer * backbuffer)
|
||||
{
|
||||
GstD3D11WindowClass *klass = GST_D3D11_WINDOW_GET_CLASS (self);
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
guint present_flags = 0;
|
||||
GstVideoCropMeta *crop_meta;
|
||||
RECT input_rect = self->input_rect;
|
||||
RECT *prev_rect = &self->prev_input_rect;
|
||||
ID3D11RenderTargetView *rtv;
|
||||
GstMemory *mem;
|
||||
GstD3D11Memory *dmem;
|
||||
|
||||
if (!buffer)
|
||||
return GST_FLOW_OK;
|
||||
|
||||
{
|
||||
GstMapInfo infos[GST_VIDEO_MAX_PLANES];
|
||||
ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
|
||||
ID3D11VideoProcessorInputView *piv = NULL;
|
||||
ID3D11Device *device_handle =
|
||||
gst_d3d11_device_get_device_handle (self->device);
|
||||
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)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't map buffer");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
can_convert = gst_d3d11_buffer_get_shader_resource_view (buffer, srv);
|
||||
if (pov) {
|
||||
can_process = gst_d3d11_window_buffer_ensure_processor_input (self,
|
||||
buffer, &piv);
|
||||
}
|
||||
|
||||
if (!can_convert && !can_process) {
|
||||
GST_ERROR_OBJECT (self, "Input texture cannot be used for converter");
|
||||
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;
|
||||
|
||||
viewport.TopLeftX = self->render_rect.left;
|
||||
viewport.TopLeftY = self->render_rect.top;
|
||||
viewport.Width = self->render_rect.right - self->render_rect.left;
|
||||
viewport.Height = self->render_rect.bottom - self->render_rect.top;
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
|
||||
g_object_set (self->converter, "dest-x", (gint) self->render_rect.left,
|
||||
"dest-y", (gint) self->render_rect.top,
|
||||
"dest-width",
|
||||
(gint) (self->render_rect.right - self->render_rect.left),
|
||||
"dest-height",
|
||||
(gint) (self->render_rect.bottom - self->render_rect.top), nullptr);
|
||||
gst_d3d11_overlay_compositor_update_viewport (self->compositor,
|
||||
&viewport);
|
||||
}
|
||||
|
||||
/* Converter preference order
|
||||
* 1) If this texture can be converted via processor, and we used processor
|
||||
* previously, use processor
|
||||
* 2) If SRV is available, use converter
|
||||
* 3) otherwise, use processor
|
||||
*/
|
||||
if (can_process && self->processor_in_use) {
|
||||
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, &input_rect);
|
||||
} else if (can_process) {
|
||||
convert_ret = gst_d3d11_window_do_processor (self, piv, pov, &input_rect);
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
ret = GST_FLOW_ERROR;
|
||||
goto unmap_and_out;
|
||||
}
|
||||
|
||||
if (!convert_ret) {
|
||||
ret = GST_FLOW_ERROR;
|
||||
goto unmap_and_out;
|
||||
}
|
||||
|
||||
gst_d3d11_overlay_compositor_upload (self->compositor, buffer);
|
||||
gst_d3d11_overlay_compositor_draw_unlocked (self->compositor, &rtv);
|
||||
|
||||
if (self->allow_tearing && self->fullscreen) {
|
||||
present_flags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||
}
|
||||
|
||||
if (klass->present)
|
||||
ret = klass->present (self, present_flags);
|
||||
|
||||
self->first_present = FALSE;
|
||||
|
||||
unmap_and_out:
|
||||
gst_d3d11_buffer_unmap (buffer, infos);
|
||||
if (!backbuffer) {
|
||||
GST_ERROR_OBJECT (self, "Empty render target");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
mem = gst_buffer_peek_memory (backbuffer, 0);
|
||||
if (!gst_is_d3d11_memory (mem)) {
|
||||
GST_ERROR_OBJECT (self, "Invalid back buffer");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
dmem = GST_D3D11_MEMORY_CAST (mem);
|
||||
rtv = gst_d3d11_memory_get_render_target_view (dmem, 0);
|
||||
if (!rtv) {
|
||||
GST_ERROR_OBJECT (self, "RTV is unavailable");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
crop_meta = gst_buffer_get_video_crop_meta (buffer);
|
||||
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 (input_rect.left != prev_rect->left || input_rect.top != prev_rect->top ||
|
||||
input_rect.right != prev_rect->right ||
|
||||
input_rect.bottom != prev_rect->bottom) {
|
||||
g_object_set (self->converter, "src-x", (gint) input_rect.left,
|
||||
"src-y", (gint) input_rect.top,
|
||||
"src-width", (gint) (input_rect.right - input_rect.left),
|
||||
"src-height", (gint) (input_rect.bottom - input_rect.top), nullptr);
|
||||
|
||||
self->prev_input_rect = input_rect;
|
||||
}
|
||||
|
||||
if (self->first_present) {
|
||||
D3D11_VIEWPORT viewport;
|
||||
|
||||
viewport.TopLeftX = self->render_rect.left;
|
||||
viewport.TopLeftY = self->render_rect.top;
|
||||
viewport.Width = self->render_rect.right - self->render_rect.left;
|
||||
viewport.Height = self->render_rect.bottom - self->render_rect.top;
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
|
||||
g_object_set (self->converter, "dest-x", (gint) self->render_rect.left,
|
||||
"dest-y", (gint) self->render_rect.top,
|
||||
"dest-width",
|
||||
(gint) (self->render_rect.right - self->render_rect.left),
|
||||
"dest-height",
|
||||
(gint) (self->render_rect.bottom - self->render_rect.top), nullptr);
|
||||
gst_d3d11_overlay_compositor_update_viewport (self->compositor, &viewport);
|
||||
}
|
||||
|
||||
if (!gst_d3d11_converter_convert_buffer_unlocked (self->converter,
|
||||
buffer, backbuffer)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't render buffer");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
gst_d3d11_overlay_compositor_upload (self->compositor, buffer);
|
||||
gst_d3d11_overlay_compositor_draw_unlocked (self->compositor, &rtv);
|
||||
|
||||
if (self->allow_tearing && self->fullscreen)
|
||||
present_flags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||
|
||||
if (klass->present)
|
||||
ret = klass->present (self, present_flags);
|
||||
|
||||
self->first_present = FALSE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GstFlowReturn
|
||||
gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer)
|
||||
{
|
||||
GstMemory *mem;
|
||||
GstFlowReturn ret;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), GST_FLOW_ERROR);
|
||||
|
||||
if (buffer) {
|
||||
mem = gst_buffer_peek_memory (buffer, 0);
|
||||
if (!gst_is_d3d11_memory (mem)) {
|
||||
GST_ERROR_OBJECT (window, "Invalid buffer");
|
||||
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
gst_d3d11_device_lock (window->device);
|
||||
if (buffer)
|
||||
gst_buffer_replace (&window->cached_buffer, buffer);
|
||||
|
||||
ret = gst_d3d111_window_present (window, window->cached_buffer,
|
||||
window->pov, window->rtv);
|
||||
window->backbuffer);
|
||||
gst_d3d11_device_unlock (window->device);
|
||||
|
||||
return ret;
|
||||
|
@ -1029,11 +848,8 @@ gst_d3d11_window_render_on_shared_handle (GstD3D11Window * window,
|
|||
guint64 acquire_key, guint64 release_key)
|
||||
{
|
||||
GstD3D11WindowClass *klass;
|
||||
GstMemory *mem;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstD3D11WindowSharedHandleData data = { NULL, };
|
||||
ID3D11VideoProcessorOutputView *pov = NULL;
|
||||
ID3D11RenderTargetView *rtv = NULL;
|
||||
GstD3D11WindowSharedHandleData data = { nullptr, };
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), GST_FLOW_ERROR);
|
||||
|
||||
|
@ -1042,13 +858,6 @@ gst_d3d11_window_render_on_shared_handle (GstD3D11Window * window,
|
|||
g_assert (klass->open_shared_handle != NULL);
|
||||
g_assert (klass->release_shared_handle != NULL);
|
||||
|
||||
mem = gst_buffer_peek_memory (buffer, 0);
|
||||
if (!gst_is_d3d11_memory (mem)) {
|
||||
GST_ERROR_OBJECT (window, "Invalid buffer");
|
||||
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
data.shared_handle = shared_handle;
|
||||
data.texture_misc_flags = texture_misc_flags;
|
||||
data.acquire_key = acquire_key;
|
||||
|
@ -1061,15 +870,7 @@ gst_d3d11_window_render_on_shared_handle (GstD3D11Window * window,
|
|||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
if (data.fallback_rtv) {
|
||||
rtv = data.fallback_rtv;
|
||||
pov = data.fallback_pov;
|
||||
} else {
|
||||
rtv = data.rtv;
|
||||
pov = data.pov;
|
||||
}
|
||||
|
||||
ret = gst_d3d111_window_present (window, buffer, pov, rtv);
|
||||
ret = gst_d3d111_window_present (window, buffer, data.render_target);
|
||||
|
||||
klass->release_shared_handle (window, &data);
|
||||
gst_d3d11_device_unlock (window->device);
|
||||
|
|
|
@ -69,13 +69,8 @@ typedef struct
|
|||
guint64 acquire_key;
|
||||
guint64 release_key;
|
||||
|
||||
ID3D11Texture2D *texture;
|
||||
GstBuffer *render_target;
|
||||
IDXGIKeyedMutex *keyed_mutex;
|
||||
ID3D11VideoProcessorOutputView *pov;
|
||||
ID3D11RenderTargetView *rtv;
|
||||
|
||||
ID3D11VideoProcessorOutputView *fallback_pov;
|
||||
ID3D11RenderTargetView *fallback_rtv;
|
||||
} GstD3D11WindowSharedHandleData;
|
||||
|
||||
struct _GstD3D11Window
|
||||
|
@ -85,6 +80,7 @@ struct _GstD3D11Window
|
|||
/*< protected >*/
|
||||
gboolean initialized;
|
||||
GstD3D11Device *device;
|
||||
GstD3D11Allocator *allocator;
|
||||
guintptr external_handle;
|
||||
|
||||
/* properties */
|
||||
|
@ -97,12 +93,9 @@ struct _GstD3D11Window
|
|||
|
||||
GstVideoInfo info;
|
||||
GstVideoInfo render_info;
|
||||
GstD3D11VideoProcessor *processor;
|
||||
GstD3D11Converter *converter;
|
||||
GstD3D11OverlayCompositor *compositor;
|
||||
|
||||
gboolean processor_in_use;
|
||||
|
||||
/* calculated rect with aspect ratio and window area */
|
||||
RECT render_rect;
|
||||
|
||||
|
@ -117,8 +110,7 @@ struct _GstD3D11Window
|
|||
guint surface_height;
|
||||
|
||||
IDXGISwapChain *swap_chain;
|
||||
ID3D11RenderTargetView *rtv;
|
||||
ID3D11VideoProcessorOutputView *pov;
|
||||
GstBuffer *backbuffer;
|
||||
DXGI_FORMAT dxgi_format;
|
||||
|
||||
GstBuffer *cached_buffer;
|
||||
|
@ -158,7 +150,6 @@ struct _GstD3D11WindowClass
|
|||
guint display_width,
|
||||
guint display_height,
|
||||
GstCaps * caps,
|
||||
gboolean * video_processor_available,
|
||||
GError ** error);
|
||||
|
||||
void (*unprepare) (GstD3D11Window * window);
|
||||
|
@ -190,7 +181,6 @@ gboolean gst_d3d11_window_prepare (GstD3D11Window * window,
|
|||
guint display_width,
|
||||
guint display_height,
|
||||
GstCaps * caps,
|
||||
gboolean * video_processor_available,
|
||||
GError ** error);
|
||||
|
||||
GstFlowReturn gst_d3d11_window_render (GstD3D11Window * window,
|
||||
|
|
|
@ -49,9 +49,7 @@ G_DEFINE_TYPE (GstD3D11WindowDummy, gst_d3d11_window_dummy,
|
|||
static void gst_d3d11_window_dummy_on_resize (GstD3D11Window * window,
|
||||
guint width, guint height);
|
||||
static gboolean gst_d3d11_window_dummy_prepare (GstD3D11Window * window,
|
||||
guint display_width, guint display_height, GstCaps * caps,
|
||||
gboolean * video_processor_available, GError ** error);
|
||||
static void gst_d3d11_window_dummy_unprepare (GstD3D11Window * window);
|
||||
guint display_width, guint display_height, GstCaps * caps, GError ** error);
|
||||
static gboolean
|
||||
gst_d3d11_window_dummy_open_shared_handle (GstD3D11Window * window,
|
||||
GstD3D11WindowSharedHandleData * data);
|
||||
|
@ -67,8 +65,6 @@ gst_d3d11_window_dummy_class_init (GstD3D11WindowDummyClass * klass)
|
|||
window_class->on_resize =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_dummy_on_resize);
|
||||
window_class->prepare = GST_DEBUG_FUNCPTR (gst_d3d11_window_dummy_prepare);
|
||||
window_class->unprepare =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_dummy_unprepare);
|
||||
window_class->open_shared_handle =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_dummy_open_shared_handle);
|
||||
window_class->release_shared_handle =
|
||||
|
@ -82,13 +78,19 @@ gst_d3d11_window_dummy_init (GstD3D11WindowDummy * self)
|
|||
|
||||
static gboolean
|
||||
gst_d3d11_window_dummy_prepare (GstD3D11Window * window,
|
||||
guint display_width, guint display_height, GstCaps * caps,
|
||||
gboolean * video_processor_available, GError ** error)
|
||||
guint display_width, guint display_height, GstCaps * caps, GError ** error)
|
||||
{
|
||||
GstDxgiColorSpace in_space;
|
||||
GstD3D11ConverterMethod method = GST_D3D11_CONVERTER_METHOD_SHADER;
|
||||
|
||||
g_clear_pointer (&window->processor, gst_d3d11_video_processor_free);
|
||||
if (!window->allocator) {
|
||||
window->allocator =
|
||||
(GstD3D11Allocator *) gst_allocator_find (GST_D3D11_MEMORY_NAME);
|
||||
if (!window->allocator) {
|
||||
GST_ERROR_OBJECT (window, "Allocator is unavailable");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gst_clear_object (&window->compositor);
|
||||
gst_clear_object (&window->converter);
|
||||
|
||||
|
@ -116,63 +118,7 @@ gst_d3d11_window_dummy_prepare (GstD3D11Window * window,
|
|||
window->render_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
|
||||
|
||||
gst_d3d11_device_lock (window->device);
|
||||
|
||||
if (gst_d3d11_video_info_to_dxgi_color_space (&window->info, &in_space)) {
|
||||
GstD3D11Format in_format;
|
||||
gboolean hardware = FALSE;
|
||||
GstD3D11VideoProcessor *processor = NULL;
|
||||
guint i;
|
||||
DXGI_FORMAT formats_to_check[] = {
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
DXGI_FORMAT_R10G10B10A2_UNORM
|
||||
};
|
||||
DXGI_FORMAT in_dxgi_format;
|
||||
|
||||
gst_d3d11_device_get_format (window->device,
|
||||
GST_VIDEO_INFO_FORMAT (&window->info), &in_format);
|
||||
in_dxgi_format = in_format.dxgi_format;
|
||||
|
||||
if (in_format.dxgi_format != DXGI_FORMAT_UNKNOWN) {
|
||||
g_object_get (window->device, "hardware", &hardware, NULL);
|
||||
}
|
||||
|
||||
if (hardware) {
|
||||
processor =
|
||||
gst_d3d11_video_processor_new (window->device,
|
||||
GST_VIDEO_INFO_WIDTH (&window->info),
|
||||
GST_VIDEO_INFO_HEIGHT (&window->info), display_width, display_height);
|
||||
}
|
||||
|
||||
/* Check if video processor can support all possible output dxgi formats */
|
||||
for (i = 0; i < G_N_ELEMENTS (formats_to_check) && processor; i++) {
|
||||
DXGI_FORMAT out_dxgi_format = formats_to_check[i];
|
||||
DXGI_COLOR_SPACE_TYPE in_dxgi_color_space =
|
||||
(DXGI_COLOR_SPACE_TYPE) in_space.dxgi_color_space_type;
|
||||
|
||||
if (!gst_d3d11_video_processor_check_format_conversion (processor,
|
||||
in_dxgi_format, in_dxgi_color_space, out_dxgi_format,
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709)) {
|
||||
GST_DEBUG_OBJECT (window, "Conversion is not supported by device");
|
||||
g_clear_pointer (&processor, gst_d3d11_video_processor_free);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (processor) {
|
||||
gst_d3d11_video_processor_set_input_dxgi_color_space (processor,
|
||||
(DXGI_COLOR_SPACE_TYPE) in_space.dxgi_color_space_type);
|
||||
gst_d3d11_video_processor_set_output_dxgi_color_space (processor,
|
||||
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
|
||||
}
|
||||
|
||||
window->processor = processor;
|
||||
}
|
||||
|
||||
*video_processor_available = !!window->processor;
|
||||
|
||||
window->converter =
|
||||
gst_d3d11_converter_new (window->device, &window->info,
|
||||
window->converter = gst_d3d11_converter_new (window->device, &window->info,
|
||||
&window->render_info, &method);
|
||||
|
||||
if (!window->converter) {
|
||||
|
@ -201,22 +147,6 @@ error:
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_dummy_clear_resources (GstD3D11WindowDummy * self)
|
||||
{
|
||||
GST_D3D11_CLEAR_COM (self->fallback_pov);
|
||||
GST_D3D11_CLEAR_COM (self->fallback_rtv);
|
||||
GST_D3D11_CLEAR_COM (self->fallback_texture);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_dummy_unprepare (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowDummy *self = GST_D3D11_WINDOW_DUMMY (window);
|
||||
|
||||
gst_d3d11_window_dummy_clear_resources (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_dummy_on_resize (GstD3D11Window * window,
|
||||
guint width, guint height)
|
||||
|
@ -247,108 +177,26 @@ gst_d3d11_window_dummy_on_resize (GstD3D11Window * window,
|
|||
window->first_present = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_dummy_setup_fallback_texture (GstD3D11Window * window,
|
||||
D3D11_TEXTURE2D_DESC * shared_desc)
|
||||
{
|
||||
GstD3D11WindowDummy *self = GST_D3D11_WINDOW_DUMMY (window);
|
||||
D3D11_TEXTURE2D_DESC desc = { 0, };
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc;
|
||||
ID3D11Device *device_handle =
|
||||
gst_d3d11_device_get_device_handle (window->device);
|
||||
gboolean need_new_texture = FALSE;
|
||||
HRESULT hr;
|
||||
|
||||
if (!self->fallback_texture) {
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"We have no configured fallback texture, create new one");
|
||||
need_new_texture = TRUE;
|
||||
} else {
|
||||
self->fallback_texture->GetDesc (&desc);
|
||||
if (shared_desc->Format != desc.Format) {
|
||||
GST_DEBUG_OBJECT (self, "Texture formats are different, create new one");
|
||||
need_new_texture = TRUE;
|
||||
} else if (shared_desc->Width > desc.Width ||
|
||||
shared_desc->Height > desc.Height) {
|
||||
GST_DEBUG_OBJECT (self, "Needs larger size of fallback texture");
|
||||
need_new_texture = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!need_new_texture)
|
||||
return TRUE;
|
||||
|
||||
gst_d3d11_window_dummy_clear_resources (self);
|
||||
|
||||
desc.Width = shared_desc->Width;
|
||||
desc.Height = shared_desc->Height;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = shared_desc->Format;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
|
||||
|
||||
hr = device_handle->CreateTexture2D (&desc, NULL, &self->fallback_texture);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't create fallback texture");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rtv_desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
rtv_desc.Texture2D.MipSlice = 0;
|
||||
|
||||
hr = device_handle->CreateRenderTargetView (self->fallback_texture, &rtv_desc,
|
||||
&self->fallback_rtv);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"Couldn't get render target view from fallback texture");
|
||||
gst_d3d11_window_dummy_clear_resources (self);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (window->processor) {
|
||||
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC pov_desc;
|
||||
|
||||
pov_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
|
||||
pov_desc.Texture2D.MipSlice = 0;
|
||||
|
||||
if (!gst_d3d11_video_processor_create_output_view (window->processor,
|
||||
&pov_desc, self->fallback_texture, &self->fallback_pov)) {
|
||||
GST_ERROR_OBJECT (window,
|
||||
"ID3D11VideoProcessorOutputView is unavailable");
|
||||
gst_d3d11_window_dummy_clear_resources (self);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static gboolean
|
||||
gst_d3d11_window_dummy_open_shared_handle (GstD3D11Window * window,
|
||||
GstD3D11WindowSharedHandleData * data)
|
||||
{
|
||||
GstD3D11WindowDummy *self = GST_D3D11_WINDOW_DUMMY (window);
|
||||
GstD3D11Device *device = window->device;
|
||||
ID3D11Device *device_handle;
|
||||
HRESULT hr;
|
||||
ID3D11Texture2D *texture = NULL;
|
||||
IDXGIKeyedMutex *keyed_mutex = NULL;
|
||||
ID3D11VideoProcessorOutputView *pov = NULL;
|
||||
ID3D11RenderTargetView *rtv = NULL;
|
||||
ComPtr < ID3D11Texture2D > texture;
|
||||
ComPtr < IDXGIKeyedMutex > keyed_mutex;
|
||||
ID3D11RenderTargetView *rtv;
|
||||
GstMemory *mem;
|
||||
GstD3D11Memory *dmem;
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
gboolean use_keyed_mutex = FALSE;
|
||||
gboolean need_fallback_texture = FALSE;
|
||||
|
||||
device_handle = gst_d3d11_device_get_device_handle (device);
|
||||
|
||||
if ((data->texture_misc_flags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE) ==
|
||||
D3D11_RESOURCE_MISC_SHARED_NTHANDLE) {
|
||||
ComPtr<ID3D11Device1> device1_handle;
|
||||
ComPtr < ID3D11Device1 > device1_handle;
|
||||
|
||||
hr = device_handle->QueryInterface (IID_PPV_ARGS (&device1_handle));
|
||||
if (!gst_d3d11_result (hr, device))
|
||||
|
@ -370,82 +218,47 @@ gst_d3d11_window_dummy_open_shared_handle (GstD3D11Window * window,
|
|||
|
||||
if (use_keyed_mutex) {
|
||||
hr = texture->QueryInterface (IID_PPV_ARGS (&keyed_mutex));
|
||||
if (!gst_d3d11_result (hr, device))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (window->processor) {
|
||||
if (use_keyed_mutex) {
|
||||
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC pov_desc;
|
||||
|
||||
pov_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
|
||||
pov_desc.Texture2D.MipSlice = 0;
|
||||
|
||||
if (!gst_d3d11_video_processor_create_output_view (window->processor,
|
||||
&pov_desc, texture, &pov)) {
|
||||
GST_WARNING_OBJECT (window,
|
||||
"ID3D11VideoProcessorOutputView is unavailable");
|
||||
}
|
||||
} else {
|
||||
/* HACK: If external texture was created without keyed mutext
|
||||
* and we need to used videoprocessor to convert decoder output texture
|
||||
* to external texture, converted texture by videoprocessor seems to be broken
|
||||
* Probably that's because of missing flush/sync API around videoprocessor.
|
||||
* (e.g., ID3D11VideoContext and ID3D11VideoProcessor have no
|
||||
* flushing api such as ID3D11DeviceContext::Flush).
|
||||
* To workaround the case, we need to use fallback texture and copy back
|
||||
* to external texture
|
||||
*/
|
||||
|
||||
need_fallback_texture = TRUE;
|
||||
|
||||
GST_TRACE_OBJECT (window,
|
||||
"We are using video processor but keyed mutex is unavailable");
|
||||
if (!gst_d3d11_window_dummy_setup_fallback_texture (window, &desc)) {
|
||||
goto out;
|
||||
}
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_ERROR_OBJECT (window, "Keyed mutex is unavailable");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
hr = device_handle->CreateRenderTargetView ((ID3D11Resource *) texture,
|
||||
NULL, &rtv);
|
||||
if (!gst_d3d11_result (hr, device))
|
||||
goto out;
|
||||
mem = gst_d3d11_allocator_alloc_wrapped_native_size (window->allocator,
|
||||
device, texture.Get (), nullptr, nullptr);
|
||||
if (!mem) {
|
||||
GST_ERROR_OBJECT (window, "Couldn't allocate memory");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dmem = GST_D3D11_MEMORY_CAST (mem);
|
||||
rtv = gst_d3d11_memory_get_render_target_view (dmem, 0);
|
||||
if (!rtv) {
|
||||
GST_ERROR_OBJECT (window, "Render target view is unavailable");
|
||||
gst_memory_unref (mem);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (keyed_mutex) {
|
||||
hr = keyed_mutex->AcquireSync(data->acquire_key, INFINITE);
|
||||
if (!gst_d3d11_result (hr, device))
|
||||
goto out;
|
||||
hr = keyed_mutex->AcquireSync (data->acquire_key, INFINITE);
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_ERROR_OBJECT (window, "Couldn't acquire sync");
|
||||
gst_memory_unref (mem);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Everything is prepared now */
|
||||
gst_d3d11_window_dummy_on_resize (window, desc.Width, desc.Height);
|
||||
|
||||
/* Move owned resources */
|
||||
data->texture = texture;
|
||||
data->keyed_mutex = keyed_mutex;
|
||||
data->pov = pov;
|
||||
data->rtv = rtv;
|
||||
|
||||
if (need_fallback_texture) {
|
||||
data->fallback_pov = self->fallback_pov;
|
||||
data->fallback_rtv = self->fallback_rtv;
|
||||
} else {
|
||||
data->fallback_pov = nullptr;
|
||||
data->fallback_rtv = nullptr;
|
||||
}
|
||||
data->render_target = gst_buffer_new ();
|
||||
gst_buffer_append_memory (data->render_target, mem);
|
||||
if (keyed_mutex)
|
||||
data->keyed_mutex = keyed_mutex.Detach ();
|
||||
|
||||
return TRUE;
|
||||
|
||||
out:
|
||||
GST_D3D11_CLEAR_COM (texture);
|
||||
GST_D3D11_CLEAR_COM (keyed_mutex);
|
||||
GST_D3D11_CLEAR_COM (pov);
|
||||
GST_D3D11_CLEAR_COM (rtv);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
/* *INDENT-ON* */
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_dummy_release_shared_handle (GstD3D11Window * window,
|
||||
|
@ -460,7 +273,7 @@ gst_d3d11_window_dummy_release_shared_handle (GstD3D11Window * window,
|
|||
hr = data->keyed_mutex->ReleaseSync (data->release_key);
|
||||
gst_d3d11_result (hr, device);
|
||||
|
||||
data->keyed_mutex->Release ();
|
||||
GST_D3D11_CLEAR_COM (data->keyed_mutex);
|
||||
} else {
|
||||
/* *INDENT-OFF* */
|
||||
ComPtr<ID3D11Query> query;
|
||||
|
@ -482,30 +295,11 @@ gst_d3d11_window_dummy_release_shared_handle (GstD3D11Window * window,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* Copy from fallback texture to user's texture */
|
||||
if (data->fallback_rtv) {
|
||||
D3D11_BOX src_box;
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
ID3D11DeviceContext *context_handle =
|
||||
gst_d3d11_device_get_device_context_handle (device);
|
||||
|
||||
data->texture->GetDesc (&desc);
|
||||
|
||||
src_box.left = 0;
|
||||
src_box.top = 0;
|
||||
src_box.front = 0;
|
||||
src_box.back = 1;
|
||||
src_box.right = desc.Width;
|
||||
src_box.bottom = desc.Height;
|
||||
|
||||
context_handle->CopySubresourceRegion (data->texture, 0, 0, 0, 0,
|
||||
self->fallback_texture, 0, &src_box);
|
||||
}
|
||||
context_handle->End (query.Get ());
|
||||
|
||||
/* Wait until all issued GPU commands are finished */
|
||||
do {
|
||||
context_handle->GetData (query.Get (), &sync_done, sizeof (BOOL), 0);
|
||||
hr = context_handle->GetData (query.Get (), &sync_done, sizeof (BOOL), 0);
|
||||
} while (!sync_done && (hr == S_OK || hr == S_FALSE));
|
||||
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
|
@ -514,9 +308,7 @@ gst_d3d11_window_dummy_release_shared_handle (GstD3D11Window * window,
|
|||
}
|
||||
}
|
||||
|
||||
GST_D3D11_CLEAR_COM (data->rtv);
|
||||
GST_D3D11_CLEAR_COM (data->pov);
|
||||
GST_D3D11_CLEAR_COM (data->texture);
|
||||
gst_clear_buffer (&data->render_target);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue