mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
258 lines
7.3 KiB
C++
258 lines
7.3 KiB
C++
|
/* GStreamer
|
||
|
* Copyright (C) 2022 Matthew Waters <matthew@centricular.com>
|
||
|
* Copyright (C) 2023 Seungha Yang <seungha@centricular.com>
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Library General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Library General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Library General Public
|
||
|
* License along with this library; if not, write to the
|
||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||
|
* Boston, MA 02110-1301, USA.
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include "gstqsg6d3d11node.h"
|
||
|
#include <wrl.h>
|
||
|
|
||
|
GST_DEBUG_CATEGORY_EXTERN (gst_qt6_d3d11_debug);
|
||
|
#define GST_CAT_DEFAULT gst_qt6_d3d11_debug
|
||
|
|
||
|
/* *INDENT-OFF* */
|
||
|
using namespace Microsoft::WRL;
|
||
|
/* *INDENT-ON* */
|
||
|
|
||
|
GstQSG6D3D11Node::GstQSG6D3D11Node (QQuickItem * item, GstD3D11Device * device)
|
||
|
{
|
||
|
window_ = item->window ();
|
||
|
qt_device_ = (GstD3D11Device *) gst_object_ref (device);
|
||
|
|
||
|
frame_.buffer = nullptr;
|
||
|
|
||
|
gst_video_info_init (&render_info_);
|
||
|
gst_video_info_init (&info_);
|
||
|
|
||
|
setOwnsTexture (true);
|
||
|
resize (8, 8);
|
||
|
|
||
|
mapTexture ();
|
||
|
}
|
||
|
|
||
|
GstQSG6D3D11Node::~GstQSG6D3D11Node ()
|
||
|
{
|
||
|
GST_DEBUG ("Destroying %p", this);
|
||
|
|
||
|
unmapTexture ();
|
||
|
gst_clear_buffer (&sharable_);
|
||
|
gst_clear_buffer (&backbuffer_);
|
||
|
gst_clear_buffer (&buffer_);
|
||
|
gst_clear_caps (&caps_);
|
||
|
|
||
|
if (pool_) {
|
||
|
gst_buffer_pool_set_active (pool_, FALSE);
|
||
|
gst_object_unref (pool_);
|
||
|
}
|
||
|
|
||
|
gst_clear_object (&conv_);
|
||
|
gst_clear_object (&device_);
|
||
|
gst_clear_object (&qt_device_);
|
||
|
}
|
||
|
|
||
|
QSGTexture *
|
||
|
GstQSG6D3D11Node::texture () const
|
||
|
{
|
||
|
return QSGSimpleTextureNode::texture ();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
GstQSG6D3D11Node::mapTexture ()
|
||
|
{
|
||
|
if (backbuffer_) {
|
||
|
gst_video_frame_map (&frame_, &render_info_, backbuffer_,
|
||
|
(GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
GstQSG6D3D11Node::unmapTexture ()
|
||
|
{
|
||
|
if (frame_.buffer)
|
||
|
gst_video_frame_unmap (&frame_);
|
||
|
frame_.buffer = nullptr;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
GstQSG6D3D11Node::resize (guint width, guint height)
|
||
|
{
|
||
|
GstStructure *config;
|
||
|
GstD3D11AllocationParams *params;
|
||
|
GstCaps *caps;
|
||
|
GstD3D11Memory *dmem;
|
||
|
ID3D11Texture2D *tex;
|
||
|
|
||
|
if (pool_ && width == render_info_.width && height == render_info_.height)
|
||
|
return;
|
||
|
|
||
|
gst_clear_buffer (&sharable_);
|
||
|
gst_clear_buffer (&backbuffer_);
|
||
|
|
||
|
if (pool_) {
|
||
|
gst_buffer_pool_set_active (pool_, FALSE);
|
||
|
gst_clear_object (&pool_);
|
||
|
}
|
||
|
|
||
|
pool_ = gst_d3d11_buffer_pool_new (qt_device_);
|
||
|
|
||
|
gst_video_info_set_format (&render_info_, GST_VIDEO_FORMAT_RGBA,
|
||
|
width, height);
|
||
|
render_info_.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
|
||
|
caps = gst_video_info_to_caps (&render_info_);
|
||
|
|
||
|
params = gst_d3d11_allocation_params_new (qt_device_, &render_info_,
|
||
|
GST_D3D11_ALLOCATION_FLAG_DEFAULT,
|
||
|
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
|
||
|
D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX);
|
||
|
|
||
|
config = gst_buffer_pool_get_config (pool_);
|
||
|
gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
|
||
|
gst_d3d11_allocation_params_free (params);
|
||
|
|
||
|
gst_buffer_pool_config_set_params (config, caps, render_info_.size, 0, 0);
|
||
|
gst_caps_unref (caps);
|
||
|
gst_buffer_pool_set_config (pool_, config);
|
||
|
gst_buffer_pool_set_active (pool_, TRUE);
|
||
|
|
||
|
gst_buffer_pool_acquire_buffer (pool_, &backbuffer_, nullptr);
|
||
|
|
||
|
dmem = (GstD3D11Memory *) gst_buffer_peek_memory (backbuffer_, 0);
|
||
|
tex = (ID3D11Texture2D *) gst_d3d11_memory_get_resource_handle (dmem);
|
||
|
auto qt_texture = QNativeInterface::QSGD3D11Texture::fromNative (tex, window_,
|
||
|
QSize (render_info_.width, render_info_.height),
|
||
|
QQuickWindow::TextureHasAlphaChannel);
|
||
|
setTexture (qt_texture);
|
||
|
}
|
||
|
|
||
|
/* only called from QT rendering thread */
|
||
|
void
|
||
|
GstQSG6D3D11Node::SetCaps (GstCaps * caps)
|
||
|
{
|
||
|
if (caps_ && caps && gst_caps_is_equal (caps_, caps))
|
||
|
return;
|
||
|
|
||
|
gst_clear_object (&conv_);
|
||
|
gst_clear_buffer (&sharable_);
|
||
|
gst_clear_buffer (&buffer_);
|
||
|
|
||
|
if (caps)
|
||
|
gst_video_info_from_caps (&info_, caps);
|
||
|
else
|
||
|
gst_video_info_init (&info_);
|
||
|
|
||
|
gst_caps_replace (&caps_, caps);
|
||
|
}
|
||
|
|
||
|
/* only called from QT rendering thread */
|
||
|
void
|
||
|
GstQSG6D3D11Node::SetBuffer (GstBuffer * buffer)
|
||
|
{
|
||
|
gboolean buffer_changed;
|
||
|
|
||
|
buffer_changed = gst_buffer_replace (&buffer_, buffer);
|
||
|
|
||
|
unmapTexture ();
|
||
|
|
||
|
if (buffer_ && buffer_changed) {
|
||
|
GstD3D11Memory *dmem;
|
||
|
|
||
|
resize (info_.width, info_.height);
|
||
|
|
||
|
dmem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
|
||
|
if (dmem->device != device_) {
|
||
|
gst_clear_object (&conv_);
|
||
|
gst_clear_buffer (&sharable_);
|
||
|
gst_clear_object (&device_);
|
||
|
device_ = (GstD3D11Device *) gst_object_ref (dmem->device);
|
||
|
}
|
||
|
|
||
|
gst_d3d11_device_lock (device_);
|
||
|
if (!conv_)
|
||
|
conv_ = gst_d3d11_converter_new (device_, &info_, &render_info_, nullptr);
|
||
|
|
||
|
if (!sharable_) {
|
||
|
GstMemory *mem_wrapped;
|
||
|
ID3D11Resource *resource;
|
||
|
ComPtr < IDXGIResource > dxgi_resource;
|
||
|
ComPtr < ID3D11Texture2D > shared_texture;
|
||
|
ID3D11Device *device_handle;
|
||
|
HANDLE handle;
|
||
|
|
||
|
device_handle = gst_d3d11_device_get_device_handle (dmem->device);
|
||
|
dmem = (GstD3D11Memory *) gst_buffer_peek_memory (backbuffer_, 0);
|
||
|
resource = gst_d3d11_memory_get_resource_handle (dmem);
|
||
|
resource->QueryInterface (IID_PPV_ARGS (&dxgi_resource));
|
||
|
dxgi_resource->GetSharedHandle (&handle);
|
||
|
device_handle->OpenSharedResource (handle,
|
||
|
IID_PPV_ARGS (&shared_texture));
|
||
|
|
||
|
mem_wrapped = gst_d3d11_allocator_alloc_wrapped (nullptr, device_,
|
||
|
shared_texture.Get (), render_info_.size, nullptr, nullptr);
|
||
|
|
||
|
sharable_ = gst_buffer_new ();
|
||
|
gst_buffer_append_memory (sharable_, mem_wrapped);
|
||
|
}
|
||
|
|
||
|
if (GST_VIDEO_INFO_FORMAT (&info_) == GST_VIDEO_FORMAT_RGBA) {
|
||
|
GstMapInfo src_info, dst_info;
|
||
|
GstMemory *src_mem, *dst_mem;
|
||
|
D3D11_TEXTURE2D_DESC src_desc, dst_desc;
|
||
|
D3D11_BOX src_box;
|
||
|
ID3D11Texture2D *src_tex, *dst_tex;
|
||
|
ID3D11DeviceContext *context =
|
||
|
gst_d3d11_device_get_device_context_handle (device_);
|
||
|
|
||
|
src_mem = gst_buffer_peek_memory (buffer_, 0);
|
||
|
dst_mem = gst_buffer_peek_memory (sharable_, 0);
|
||
|
|
||
|
gst_memory_map (src_mem, &src_info,
|
||
|
(GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11));
|
||
|
gst_memory_map (dst_mem,
|
||
|
&dst_info, (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11));
|
||
|
|
||
|
src_tex = (ID3D11Texture2D *) src_info.data;
|
||
|
dst_tex = (ID3D11Texture2D *) dst_info.data;
|
||
|
|
||
|
src_tex->GetDesc (&src_desc);
|
||
|
dst_tex->GetDesc (&dst_desc);
|
||
|
|
||
|
src_box.left = 0;
|
||
|
src_box.top = 0;
|
||
|
src_box.front = 0;
|
||
|
src_box.back = 1;
|
||
|
src_box.right = MIN (src_desc.Width, dst_desc.Width);
|
||
|
src_box.bottom = MIN (src_desc.Height, dst_desc.Height);
|
||
|
|
||
|
context->CopySubresourceRegion (dst_tex, 0,
|
||
|
0, 0, 0, src_tex, 0, &src_box);
|
||
|
gst_memory_unmap (src_mem, &src_info);
|
||
|
gst_memory_unmap (dst_mem, &dst_info);
|
||
|
} else {
|
||
|
gst_d3d11_converter_convert_buffer_unlocked (conv_, buffer_, sharable_);
|
||
|
}
|
||
|
gst_d3d11_device_unlock (device_);
|
||
|
|
||
|
markDirty (QSGNode::DirtyMaterial);
|
||
|
}
|
||
|
|
||
|
mapTexture ();
|
||
|
}
|