mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-13 07:02:53 +00:00
d3d12screencapturesrc: Add support for HDR capture in DDA mode
Use IDXGIOutput5::DuplicateOutput1() if HDR is enabled. Note that scRGB color space is not defined in GStreamer, this element will output SDR tonemapped frame with linear or reinhard filtering. Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3834 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8227>
This commit is contained in:
parent
2ff7b5a5ab
commit
126d6f0815
7 changed files with 484 additions and 45 deletions
|
@ -14932,7 +14932,7 @@
|
|||
"klass": "Source/Video",
|
||||
"pad-templates": {
|
||||
"src": {
|
||||
"caps": "video/x-raw(memory:D3D12Memory):\n format: BGRA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\npixel-aspect-ratio: 1/1\n colorimetry: sRGB\nvideo/x-raw:\n format: BGRA\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\npixel-aspect-ratio: 1/1\n colorimetry: sRGB\n",
|
||||
"caps": "video/x-raw(memory:D3D12Memory):\n format: { BGRA, RGBA64_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\npixel-aspect-ratio: 1/1\n colorimetry: sRGB\nvideo/x-raw:\n format: { BGRA, RGBA64_LE }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\npixel-aspect-ratio: 1/1\n colorimetry: sRGB\n",
|
||||
"direction": "src",
|
||||
"presence": "always"
|
||||
}
|
||||
|
@ -15072,6 +15072,18 @@
|
|||
"type": "gboolean",
|
||||
"writable": true
|
||||
},
|
||||
"tonemap": {
|
||||
"blurb": "Tonemapping method to use when HDR capturing is enabled",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "linear (0)",
|
||||
"mutable": "ready",
|
||||
"readable": true,
|
||||
"type": "GstD3D12ScreenCaptureTonemap",
|
||||
"writable": true
|
||||
},
|
||||
"window-capture-mode": {
|
||||
"blurb": "Window capture mode to use if \"window-handle\" is set",
|
||||
"conditionally-available": true,
|
||||
|
@ -16540,6 +16552,21 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"GstD3D12ScreenCaptureTonemap": {
|
||||
"kind": "enum",
|
||||
"values": [
|
||||
{
|
||||
"desc": "Linear scaling",
|
||||
"name": "linear",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"desc": "Reinhard tonemap",
|
||||
"name": "reinhard",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"GstD3D12TestSrcPattern": {
|
||||
"kind": "enum",
|
||||
"values": [
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include <future>
|
||||
#include <wrl.h>
|
||||
#include <gst/d3dshader/gstd3dshader.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _XM_NO_INTRINSICS_
|
||||
#include <DirectXMath.h>
|
||||
|
@ -136,6 +137,110 @@ flow_return_from_hr (ID3D11Device * device,
|
|||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
static guint
|
||||
get_sdr_white_level (PCWSTR name)
|
||||
{
|
||||
LONG ret = ERROR_SUCCESS;
|
||||
std::vector < DISPLAYCONFIG_PATH_INFO > path_info;
|
||||
std::vector < DISPLAYCONFIG_MODE_INFO > mode_info;
|
||||
gint retry_count = 0;
|
||||
guint nits = 80;
|
||||
|
||||
/* QueryDisplayConfig() may return ERROR_INSUFFICIENT_BUFFER if there was
|
||||
* configuration update between GetDisplayConfigBufferSizes() and
|
||||
* QueryDisplayConfig() call. */
|
||||
while (1) {
|
||||
UINT32 n_path = 0;
|
||||
UINT32 n_mode = 0;
|
||||
|
||||
ret = GetDisplayConfigBufferSizes (QDC_ONLY_ACTIVE_PATHS, &n_path, &n_mode);
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
GST_WARNING ("GetDisplayConfigBufferSizes failed %d", (gint) ret);
|
||||
return nits;
|
||||
}
|
||||
|
||||
path_info.resize (n_path);
|
||||
mode_info.resize (n_mode);
|
||||
|
||||
ret = QueryDisplayConfig (QDC_ONLY_ACTIVE_PATHS, &n_path, path_info.data (),
|
||||
&n_mode, mode_info.data (), nullptr);
|
||||
if (ret == ERROR_INSUFFICIENT_BUFFER) {
|
||||
/* XXX: avoid infinite loop */
|
||||
retry_count++;
|
||||
if (retry_count > 100) {
|
||||
GST_WARNING ("Too many retry, give up");
|
||||
return nits;
|
||||
}
|
||||
|
||||
GST_DEBUG ("Insufficient buffer, retrying");
|
||||
continue;
|
||||
} else if (ret != ERROR_SUCCESS) {
|
||||
GST_WARNING ("QueryDisplayConfig failed %d", (gint) ret);
|
||||
return nits;
|
||||
}
|
||||
|
||||
path_info.resize (n_path);
|
||||
mode_info.resize (n_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < path_info.size (); i++) {
|
||||
DISPLAYCONFIG_SOURCE_DEVICE_NAME src_name = { };
|
||||
src_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
|
||||
src_name.header.size = sizeof (DISPLAYCONFIG_SOURCE_DEVICE_NAME);
|
||||
src_name.header.adapterId = path_info[i].sourceInfo.adapterId;
|
||||
src_name.header.id = path_info[i].sourceInfo.id;
|
||||
|
||||
ret = DisplayConfigGetDeviceInfo (&src_name.header);
|
||||
if (ret == ERROR_SUCCESS && wcscmp (name, src_name.viewGdiDeviceName) == 0) {
|
||||
DISPLAYCONFIG_SDR_WHITE_LEVEL level;
|
||||
level.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
|
||||
level.header.size = sizeof (level);
|
||||
level.header.adapterId = path_info[i].targetInfo.adapterId;
|
||||
level.header.id = path_info[i].targetInfo.id;
|
||||
ret = DisplayConfigGetDeviceInfo (&level.header);
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
GST_WARNING ("Couldn't get SDR white level info");
|
||||
return nits;
|
||||
}
|
||||
|
||||
return (level.SDRWhiteLevel * 80) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
return nits;
|
||||
}
|
||||
|
||||
struct DxgiCaptureVTable
|
||||
{
|
||||
gboolean loaded;
|
||||
DPI_AWARENESS_CONTEXT (WINAPI * SetThreadDpiAwarenessContext) (DPI_AWARENESS_CONTEXT context);
|
||||
};
|
||||
|
||||
static DxgiCaptureVTable g_vtable = { };
|
||||
|
||||
static gboolean
|
||||
gst_d3d12_dxgi_capture_load_library (void)
|
||||
{
|
||||
static GModule *user32_module = nullptr;
|
||||
|
||||
GST_D3D12_CALL_ONCE_BEGIN {
|
||||
g_vtable.loaded = FALSE;
|
||||
user32_module = g_module_open ("user32.dll", G_MODULE_BIND_LAZY);
|
||||
if (!user32_module)
|
||||
return;
|
||||
|
||||
if (!g_module_symbol (user32_module, "SetThreadDpiAwarenessContext",
|
||||
(gpointer *) &g_vtable.SetThreadDpiAwarenessContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_vtable.loaded = TRUE;
|
||||
} GST_D3D12_CALL_ONCE_END;
|
||||
|
||||
return g_vtable.loaded;
|
||||
}
|
||||
|
||||
struct PtrInfo
|
||||
{
|
||||
PtrInfo ()
|
||||
|
@ -259,6 +364,12 @@ struct VERTEX
|
|||
XMFLOAT2 TexCoord;
|
||||
};
|
||||
|
||||
struct PSConstBuffer
|
||||
{
|
||||
float sdr_white_level;
|
||||
float padding[3];
|
||||
};
|
||||
|
||||
class DesktopDupCtx
|
||||
{
|
||||
public:
|
||||
|
@ -275,11 +386,14 @@ public:
|
|||
GstFlowReturn Init (HMONITOR monitor, ID3D11Device5 * device,
|
||||
ID3D11DeviceContext4 * context, ID3D11Fence * fence,
|
||||
ID3D11SamplerState * sampler, ID3D11PixelShader * ps,
|
||||
ID3D11VertexShader * vs, ID3D11InputLayout * layout)
|
||||
ID3D11PixelShader * ps_scrgb, ID3D11PixelShader * ps_scrgb_tonemap,
|
||||
ID3D11Buffer * ps_cbuf, ID3D11VertexShader * vs,
|
||||
ID3D11InputLayout * layout, gboolean use_reinhard)
|
||||
{
|
||||
ComPtr<IDXGIAdapter1> adapter;
|
||||
ComPtr<IDXGIOutput> output;
|
||||
ComPtr<IDXGIOutput1> output1;
|
||||
ComPtr<IDXGIOutput6> output6;
|
||||
|
||||
HRESULT hr = gst_d3d12_screen_capture_find_output_for_monitor (monitor,
|
||||
&adapter, &output);
|
||||
|
@ -294,6 +408,27 @@ public:
|
|||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
PSConstBuffer cbuf;
|
||||
cbuf.sdr_white_level = 80.0;
|
||||
gboolean is_hdr = FALSE;
|
||||
|
||||
if (gst_d3d12_dxgi_capture_load_library ()) {
|
||||
hr = output.As (&output6);
|
||||
if (SUCCEEDED (hr)) {
|
||||
DXGI_OUTPUT_DESC1 desc1;
|
||||
hr = output6->GetDesc1 (&desc1);
|
||||
if (SUCCEEDED (hr) &&
|
||||
desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
|
||||
is_hdr = TRUE;
|
||||
|
||||
MONITORINFOEXW monitor_info = { };
|
||||
monitor_info.cbSize = sizeof (MONITORINFOEXW);
|
||||
if (GetMonitorInfoW (desc1.Monitor, (LPMONITORINFO) & monitor_info))
|
||||
cbuf.sdr_white_level = get_sdr_white_level (monitor_info.szDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HDESK hdesk = OpenInputDesktop (0, FALSE, GENERIC_ALL);
|
||||
if (hdesk) {
|
||||
if (!SetThreadDesktop (hdesk)) {
|
||||
|
@ -305,8 +440,35 @@ public:
|
|||
GST_WARNING ("OpenInputDesktop() failed, error %lu", GetLastError());
|
||||
}
|
||||
|
||||
/* FIXME: Use DuplicateOutput1 to avoid potentail color conversion */
|
||||
hr = output1->DuplicateOutput(device, &dupl_);
|
||||
hr = E_FAIL;
|
||||
output_format_ = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
if (is_hdr) {
|
||||
DXGI_FORMAT formats[] = {
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||||
DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
};
|
||||
|
||||
/* XXX: DuplicateOutput1() would fail if dpi awareness is not configured */
|
||||
auto prev_ctx = g_vtable.SetThreadDpiAwarenessContext
|
||||
(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
hr = output6->DuplicateOutput1(device, 0, 2, formats, &dupl_);
|
||||
|
||||
/* And restore dpi context for the current thread */
|
||||
if (prev_ctx != nullptr)
|
||||
g_vtable.SetThreadDpiAwarenessContext (prev_ctx);
|
||||
|
||||
if (FAILED (hr)) {
|
||||
GST_WARNING ("IDXGIOutput5::DuplicateOutput1 returned 0x%x",
|
||||
(guint) hr);
|
||||
is_hdr = FALSE;
|
||||
} else {
|
||||
output_format_ = DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED (hr))
|
||||
hr = output1->DuplicateOutput(device, &dupl_);
|
||||
|
||||
if (FAILED (hr)) {
|
||||
if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
|
||||
GST_ERROR ("Hit the max allowed number of Desktop Duplication session");
|
||||
|
@ -328,14 +490,6 @@ public:
|
|||
CreateDuplicationExpectedErrors);
|
||||
}
|
||||
|
||||
device_ = device;
|
||||
context_ = context;
|
||||
shared_fence_ = fence;
|
||||
sampler_ = sampler;
|
||||
ps_ = ps;
|
||||
vs_ = vs;
|
||||
layout_ = layout;
|
||||
|
||||
dupl_->GetDesc (&output_desc_);
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = { };
|
||||
|
@ -343,23 +497,55 @@ public:
|
|||
desc.Height = output_desc_.ModeDesc.Height;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.Format = output_format_;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
|
||||
|
||||
hr = device_->CreateTexture2D (&desc, nullptr, &texture_);
|
||||
device_ = device;
|
||||
context_ = context;
|
||||
shared_fence_ = fence;
|
||||
sampler_ = sampler;
|
||||
ps_cbuf_ = ps_cbuf;
|
||||
vs_ = vs;
|
||||
layout_ = layout;
|
||||
|
||||
if (is_hdr) {
|
||||
GST_INFO ("HDR with SDR white level %d nits",
|
||||
(guint) cbuf.sdr_white_level);
|
||||
if (!use_reinhard) {
|
||||
GST_INFO ("Use scRGB sampling");
|
||||
ps_ = ps_scrgb;
|
||||
} else {
|
||||
GST_INFO ("use scRGB sampling with reinhard tonemapping");
|
||||
ps_ = ps_scrgb_tonemap;
|
||||
}
|
||||
} else {
|
||||
GST_INFO ("Monitor is SDR mode");
|
||||
ps_ = ps;
|
||||
}
|
||||
|
||||
hr = device->CreateTexture2D (&desc, nullptr, &texture_);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR ("Couldn't create texture");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
hr = device_->CreateRenderTargetView (texture_.Get (), nullptr, &rtv_);
|
||||
hr = device->CreateRenderTargetView (texture_.Get (), nullptr, &rtv_);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR ("Couldn't create render target view");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
hr = context->Map (ps_cbuf_.Get (), 0, D3D11_MAP_WRITE_DISCARD, 0, &map); if (FAILED (hr)) {
|
||||
GST_ERROR ("Couldn't map constant buffer");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
memcpy (map.pData, &cbuf, sizeof (PSConstBuffer));
|
||||
context->Unmap (ps_cbuf_.Get (), 0);
|
||||
|
||||
viewport_.TopLeftX = 0;
|
||||
viewport_.TopLeftY = 0;
|
||||
viewport_.MinDepth = 0;
|
||||
|
@ -647,6 +833,8 @@ public:
|
|||
context_->IASetInputLayout(layout_.Get());
|
||||
context_->VSSetShader(vs_.Get(), nullptr, 0);
|
||||
context_->PSSetShader(ps_.Get(), nullptr, 0);
|
||||
ID3D11Buffer *ps_cbuf[] = { ps_cbuf_.Get () };
|
||||
context_->PSSetConstantBuffers (0, 1, ps_cbuf);
|
||||
|
||||
ID3D11ShaderResourceView *srv[] = { cur_srv.Get () };
|
||||
context_->PSSetShaderResources(0, 1, srv);
|
||||
|
@ -751,6 +939,18 @@ public:
|
|||
if (hr != DXGI_ERROR_WAIT_TIMEOUT) {
|
||||
if (FAILED (hr)) {
|
||||
GST_WARNING ("AcquireNextFrame failed with 0x%x", (guint) hr);
|
||||
/* XXX: HDR <-> SDR mode switching seems to be racy,
|
||||
* and AcquireNextFrame() seems to return DXGI_ERROR_INVALID_CALL
|
||||
* sometimes on HDR <-> SDR mode switching.
|
||||
* Do return GST_D3D12_SCREEN_CAPTURE_FLOW_UNSUPPORTED here
|
||||
* if AcquireNextFrame() returns DXGI_ERROR_INVALID_CALL, then
|
||||
* source element will do retry a bit more */
|
||||
if (hr == DXGI_ERROR_INVALID_CALL) {
|
||||
GST_WARNING ("DXGI_ERROR_INVALID_CALL, trying again");
|
||||
dupl_->ReleaseFrame ();
|
||||
return GST_D3D12_SCREEN_CAPTURE_FLOW_UNSUPPORTED;
|
||||
}
|
||||
|
||||
dupl_->ReleaseFrame ();
|
||||
return flow_return_from_hr (device_.Get (), hr, FrameInfoExpectedErrors);
|
||||
}
|
||||
|
@ -777,6 +977,11 @@ public:
|
|||
*height = output_desc_.ModeDesc.Height;
|
||||
}
|
||||
|
||||
DXGI_FORMAT GetFormat ()
|
||||
{
|
||||
return output_format_;
|
||||
}
|
||||
|
||||
DXGI_OUTDUPL_DESC GetDesc ()
|
||||
{
|
||||
return output_desc_;
|
||||
|
@ -810,12 +1015,16 @@ private:
|
|||
ComPtr<ID3D11RenderTargetView> rtv_;
|
||||
ComPtr<ID3D11SamplerState> sampler_;
|
||||
ComPtr<ID3D11PixelShader> ps_;
|
||||
ComPtr<ID3D11PixelShader> ps_scrgb_;
|
||||
ComPtr<ID3D11PixelShader> ps_scrgb_tonemap_;
|
||||
ComPtr<ID3D11Buffer> ps_cbuf_;
|
||||
ComPtr<ID3D11VertexShader> vs_;
|
||||
ComPtr<ID3D11InputLayout> layout_;
|
||||
ComPtr<ID3D11Buffer> vertex_buf_;
|
||||
UINT vertext_buf_size_ = 0;
|
||||
D3D11_VIEWPORT viewport_ = { };
|
||||
std::vector<VERTEX> dirty_vertex_;
|
||||
DXGI_FORMAT output_format_ = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
|
||||
/* frame metadata */
|
||||
std::vector<BYTE> metadata_buffer_;
|
||||
|
@ -838,6 +1047,8 @@ struct GstD3D12DxgiCapturePrivate
|
|||
gst_clear_object (&fence_data_pool);
|
||||
gst_clear_object (&mouse_blend);
|
||||
gst_clear_object (&mouse_xor_blend);
|
||||
gst_clear_object (&mouse_blend_scrgb);
|
||||
gst_clear_object (&mouse_xor_blend_scrgb);
|
||||
}
|
||||
|
||||
void WaitGPU ()
|
||||
|
@ -860,17 +1071,24 @@ struct GstD3D12DxgiCapturePrivate
|
|||
ComPtr<ID3D11Fence> shared_fence11;
|
||||
ComPtr<ID3D11SamplerState> sampler;
|
||||
ComPtr<ID3D11PixelShader> ps;
|
||||
ComPtr<ID3D11PixelShader> ps_scrgb;
|
||||
ComPtr<ID3D11PixelShader> ps_scrgb_tonemap;
|
||||
ComPtr<ID3D11VertexShader> vs;
|
||||
ComPtr<ID3D11InputLayout> layout;
|
||||
ComPtr<ID3D11Buffer> const_buf;
|
||||
|
||||
GstBuffer *mouse_buf = nullptr;
|
||||
GstBuffer *mouse_xor_buf = nullptr;
|
||||
|
||||
GstD3D12Converter *mouse_blend = nullptr;
|
||||
GstD3D12Converter *mouse_xor_blend = nullptr;
|
||||
GstD3D12Converter *mouse_blend_scrgb = nullptr;
|
||||
GstD3D12Converter *mouse_xor_blend_scrgb = nullptr;
|
||||
|
||||
HMONITOR monitor_handle = nullptr;
|
||||
RECT desktop_coordinates = { };
|
||||
guint sdr_white_level = 80;
|
||||
guint prepare_flags = 0;
|
||||
|
||||
guint cached_width = 0;
|
||||
guint cached_height = 0;
|
||||
|
@ -894,10 +1112,12 @@ struct _GstD3D12DxgiCapture
|
|||
|
||||
static void gst_d3d12_dxgi_capture_finalize (GObject * object);
|
||||
static GstFlowReturn
|
||||
gst_d3d12_dxgi_capture_prepare (GstD3D12ScreenCapture * capture);
|
||||
gst_d3d12_dxgi_capture_prepare (GstD3D12ScreenCapture * capture, guint flags);
|
||||
static gboolean
|
||||
gst_d3d12_dxgi_capture_get_size (GstD3D12ScreenCapture * capture,
|
||||
guint * width, guint * height);
|
||||
static GstVideoFormat
|
||||
gst_d3d12_dxgi_capture_get_format (GstD3D12ScreenCapture * capture);
|
||||
|
||||
#define gst_d3d12_dxgi_capture_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstD3D12DxgiCapture, gst_d3d12_dxgi_capture,
|
||||
|
@ -913,6 +1133,8 @@ gst_d3d12_dxgi_capture_class_init (GstD3D12DxgiCaptureClass * klass)
|
|||
|
||||
capture_class->prepare = GST_DEBUG_FUNCPTR (gst_d3d12_dxgi_capture_prepare);
|
||||
capture_class->get_size = GST_DEBUG_FUNCPTR (gst_d3d12_dxgi_capture_get_size);
|
||||
capture_class->get_format =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d12_dxgi_capture_get_format);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -948,6 +1170,7 @@ gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self,
|
|||
priv->monitor_handle = monitor_handle;
|
||||
|
||||
ComPtr < IDXGIOutput > output;
|
||||
ComPtr < IDXGIOutput6 > output6;
|
||||
ComPtr < IDXGIAdapter1 > adapter;
|
||||
auto hr = gst_d3d12_screen_capture_find_output_for_monitor (monitor_handle,
|
||||
&adapter, &output);
|
||||
|
@ -991,6 +1214,19 @@ gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
priv->sdr_white_level = 80;
|
||||
hr = output.As (&output6);
|
||||
if (SUCCEEDED (hr)) {
|
||||
DXGI_OUTPUT_DESC1 desc1;
|
||||
hr = output6->GetDesc1 (&desc1);
|
||||
if (SUCCEEDED (hr) &&
|
||||
desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
|
||||
priv->sdr_white_level = get_sdr_white_level (monitor_info.szDevice);
|
||||
GST_INFO_OBJECT (self, "HDR mode detected, SDR white level in nits: %d",
|
||||
priv->sdr_white_level);
|
||||
}
|
||||
}
|
||||
|
||||
priv->desktop_coordinates.left = dev_mode.dmPosition.x;
|
||||
priv->desktop_coordinates.top = dev_mode.dmPosition.y;
|
||||
priv->desktop_coordinates.right =
|
||||
|
@ -1013,8 +1249,11 @@ gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self,
|
|||
|
||||
/* size will be updated later */
|
||||
GstVideoInfo info;
|
||||
GstVideoInfo scrgb_info;
|
||||
gst_video_info_set_format (&info, GST_VIDEO_FORMAT_BGRA,
|
||||
priv->cached_width, priv->cached_height);
|
||||
gst_video_info_set_format (&scrgb_info, GST_VIDEO_FORMAT_RGBA64_LE,
|
||||
priv->cached_width, priv->cached_height);
|
||||
D3D12_BLEND_DESC blend_desc = CD3DX12_BLEND_DESC (D3D12_DEFAULT);
|
||||
|
||||
blend_desc.RenderTarget[0].BlendEnable = TRUE;
|
||||
|
@ -1031,11 +1270,15 @@ gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self,
|
|||
|
||||
priv->mouse_blend = gst_d3d12_converter_new (self->device, nullptr, &info,
|
||||
&info, &blend_desc, nullptr, nullptr);
|
||||
priv->mouse_blend_scrgb = gst_d3d12_converter_new (self->device, nullptr,
|
||||
&info, &scrgb_info, &blend_desc, nullptr, nullptr);
|
||||
|
||||
blend_desc.RenderTarget[0].SrcBlend = D3D12_BLEND_INV_DEST_COLOR;
|
||||
blend_desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_COLOR;
|
||||
priv->mouse_xor_blend = gst_d3d12_converter_new (self->device, nullptr, &info,
|
||||
&info, &blend_desc, nullptr, nullptr);
|
||||
priv->mouse_xor_blend_scrgb = gst_d3d12_converter_new (self->device, nullptr,
|
||||
&info, &scrgb_info, &blend_desc, nullptr, nullptr);
|
||||
|
||||
hr = device->CreateFence (0,
|
||||
D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS (&priv->shared_fence));
|
||||
|
@ -1083,19 +1326,12 @@ gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self,
|
|||
}
|
||||
|
||||
GstD3DShaderByteCode vs_code;
|
||||
GstD3DShaderByteCode ps_code;
|
||||
if (!gst_d3d_plugin_shader_get_vs_blob (GST_D3D_PLUGIN_VS_COORD,
|
||||
GST_D3D_SM_5_0, &vs_code)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't get vs bytecode");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gst_d3d_plugin_shader_get_ps_blob (GST_D3D_PLUGIN_PS_SAMPLE,
|
||||
GST_D3D_SM_5_0, &ps_code)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't get ps bytecode");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
D3D11_INPUT_ELEMENT_DESC input_desc[2] = { };
|
||||
input_desc[0].SemanticName = "POSITION";
|
||||
input_desc[0].SemanticIndex = 0;
|
||||
|
@ -1126,6 +1362,12 @@ gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
GstD3DShaderByteCode ps_code;
|
||||
if (!gst_d3d_plugin_shader_get_ps_blob (GST_D3D_PLUGIN_PS_SAMPLE,
|
||||
GST_D3D_SM_5_0, &ps_code)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't get ps bytecode");
|
||||
return FALSE;
|
||||
}
|
||||
hr = priv->device11->CreatePixelShader (ps_code.byte_code,
|
||||
ps_code.byte_code_len, nullptr, &priv->ps);
|
||||
if (FAILED (hr)) {
|
||||
|
@ -1133,6 +1375,48 @@ gst_d3d12_dxgi_capture_open (GstD3D12DxgiCapture * self,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gst_d3d_plugin_shader_get_ps_blob (GST_D3D_PLUGIN_PS_SAMPLE_SCRGB,
|
||||
GST_D3D_SM_5_0, &ps_code)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't get ps bytecode");
|
||||
return FALSE;
|
||||
}
|
||||
hr = priv->device11->CreatePixelShader (ps_code.byte_code,
|
||||
ps_code.byte_code_len, nullptr, &priv->ps_scrgb);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't create pixel shader");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gst_d3d_plugin_shader_get_ps_blob
|
||||
(GST_D3D_PLUGIN_PS_SAMPLE_SCRGB_TONEMAP, GST_D3D_SM_5_0, &ps_code)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't get ps bytecode");
|
||||
return FALSE;
|
||||
}
|
||||
hr = priv->device11->CreatePixelShader (ps_code.byte_code,
|
||||
ps_code.byte_code_len, nullptr, &priv->ps_scrgb_tonemap);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't create pixel shader");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PSConstBuffer cbuf;
|
||||
cbuf.sdr_white_level = (float) priv->sdr_white_level;
|
||||
|
||||
D3D11_BUFFER_DESC buffer_desc = { };
|
||||
D3D11_SUBRESOURCE_DATA subresource = { };
|
||||
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
buffer_desc.ByteWidth = sizeof (PSConstBuffer);
|
||||
buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
subresource.pSysMem = &cbuf;
|
||||
subresource.SysMemPitch = sizeof (PSConstBuffer);
|
||||
hr = priv->device11->CreateBuffer (&buffer_desc, &subresource,
|
||||
&priv->const_buf);
|
||||
if (FAILED (hr)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't create constant buffer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
D3D11_SAMPLER_DESC sampler_desc = { };
|
||||
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
|
@ -1156,6 +1440,8 @@ gst_d3d12_dxgi_capture_new (GstD3D12Device * device, HMONITOR monitor_handle)
|
|||
|
||||
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), nullptr);
|
||||
|
||||
gst_d3d12_dxgi_capture_load_library ();
|
||||
|
||||
/* Check if we have dup object corresponding to monitor_handle,
|
||||
* and if there is already configured capture object, reuse it.
|
||||
* This is because of the limitation of desktop duplication API
|
||||
|
@ -1206,8 +1492,9 @@ gst_d3d12_dxgi_capture_prepare_unlocked (GstD3D12DxgiCapture * self)
|
|||
auto ctx = std::make_unique < DesktopDupCtx > ();
|
||||
auto ret = ctx->Init (priv->monitor_handle, priv->device11.Get (),
|
||||
priv->context11.Get (), priv->shared_fence11.Get (),
|
||||
priv->sampler.Get (), priv->ps.Get (), priv->vs.Get (),
|
||||
priv->layout.Get ());
|
||||
priv->sampler.Get (), priv->ps.Get (), priv->ps_scrgb.Get (),
|
||||
priv->ps_scrgb_tonemap.Get (), priv->const_buf.Get (),
|
||||
priv->vs.Get (), priv->layout.Get (), priv->prepare_flags ? TRUE : FALSE);
|
||||
if (ret != GST_FLOW_OK) {
|
||||
GST_WARNING_OBJECT (self,
|
||||
"Couldn't prepare capturing, %sexpected failure",
|
||||
|
@ -1223,12 +1510,13 @@ gst_d3d12_dxgi_capture_prepare_unlocked (GstD3D12DxgiCapture * self)
|
|||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d12_dxgi_capture_prepare (GstD3D12ScreenCapture * capture)
|
||||
gst_d3d12_dxgi_capture_prepare (GstD3D12ScreenCapture * capture, guint flags)
|
||||
{
|
||||
auto self = GST_D3D12_DXGI_CAPTURE (capture);
|
||||
auto priv = self->priv;
|
||||
|
||||
std::lock_guard < std::mutex > lk (priv->lock);
|
||||
priv->prepare_flags = flags;
|
||||
return gst_d3d12_dxgi_capture_prepare_unlocked (self);
|
||||
}
|
||||
|
||||
|
@ -1262,9 +1550,26 @@ gst_d3d12_dxgi_capture_get_size (GstD3D12ScreenCapture * capture,
|
|||
return gst_d3d12_dxgi_capture_get_size_unlocked (self, width, height);
|
||||
}
|
||||
|
||||
static GstVideoFormat
|
||||
gst_d3d12_dxgi_capture_get_format (GstD3D12ScreenCapture * capture)
|
||||
{
|
||||
auto self = GST_D3D12_DXGI_CAPTURE (capture);
|
||||
auto priv = self->priv;
|
||||
|
||||
std::lock_guard < std::mutex > lk (priv->lock);
|
||||
if (!priv->ctx)
|
||||
return GST_VIDEO_FORMAT_BGRA;
|
||||
|
||||
auto format = priv->ctx->GetFormat ();
|
||||
if (format == DXGI_FORMAT_R16G16B16A16_UNORM)
|
||||
return GST_VIDEO_FORMAT_RGBA64_LE;
|
||||
|
||||
return GST_VIDEO_FORMAT_BGRA;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self,
|
||||
GstBuffer * buffer, const D3D12_BOX * crop_box)
|
||||
GstBuffer * buffer, const D3D12_BOX * crop_box, gboolean is_hdr)
|
||||
{
|
||||
auto priv = self->priv;
|
||||
const auto & info = priv->ctx->GetPointerInfo ();
|
||||
|
@ -1404,13 +1709,15 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self,
|
|||
gint ptr_w = info.width_;
|
||||
gint ptr_h = info.height_;
|
||||
|
||||
g_object_set (priv->mouse_blend, "src-x", 0, "src-y", 0, "src-width",
|
||||
auto blend_conv = is_hdr ? priv->mouse_blend_scrgb : priv->mouse_blend;
|
||||
|
||||
g_object_set (blend_conv, "src-x", 0, "src-y", 0, "src-width",
|
||||
ptr_w, "src-height", ptr_h, "dest-x", ptr_x, "dest-y", ptr_y,
|
||||
"dest-width", ptr_w, "dest-height", ptr_h, nullptr);
|
||||
|
||||
auto cq = gst_d3d12_device_get_cmd_queue (self->device,
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT);
|
||||
if (!gst_d3d12_converter_convert_buffer (priv->mouse_blend,
|
||||
if (!gst_d3d12_converter_convert_buffer (blend_conv,
|
||||
priv->mouse_buf, buffer, fence_data, cl.Get (), TRUE)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't build mouse blend command");
|
||||
gst_d3d12_fence_data_unref (fence_data);
|
||||
|
@ -1418,11 +1725,12 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self,
|
|||
}
|
||||
|
||||
if (priv->mouse_xor_buf) {
|
||||
g_object_set (priv->mouse_xor_blend, "src-x", 0, "src-y", 0, "src-width",
|
||||
blend_conv = is_hdr ? priv->mouse_xor_blend_scrgb : priv->mouse_xor_blend;
|
||||
g_object_set (blend_conv, "src-x", 0, "src-y", 0, "src-width",
|
||||
ptr_w, "src-height", ptr_h, "dest-x", ptr_x, "dest-y", ptr_y,
|
||||
"dest-width", ptr_w, "dest-height", ptr_h, nullptr);
|
||||
|
||||
if (!gst_d3d12_converter_convert_buffer (priv->mouse_xor_blend,
|
||||
if (!gst_d3d12_converter_convert_buffer (blend_conv,
|
||||
priv->mouse_xor_buf, buffer, fence_data, cl.Get (), FALSE)) {
|
||||
GST_ERROR_OBJECT (self, "Couldn't build mouse blend command");
|
||||
gst_d3d12_fence_data_unref (fence_data);
|
||||
|
@ -1492,6 +1800,13 @@ gst_d3d12_dxgi_capture_do_capture (GstD3D12DxgiCapture * capture,
|
|||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC tex_desc;
|
||||
texture->GetDesc (&tex_desc);
|
||||
if (tex_desc.Format != priv->ctx->GetFormat ()) {
|
||||
GST_INFO_OBJECT (self, "Format mismatch");
|
||||
return GST_D3D12_SCREEN_CAPTURE_FLOW_SIZE_CHANGED;
|
||||
}
|
||||
|
||||
priv->fence_val++;
|
||||
ret = priv->ctx->Execute (texture, (D3D11_BOX *) crop_box, priv->fence_val);
|
||||
if (ret != GST_FLOW_OK) {
|
||||
|
@ -1513,7 +1828,8 @@ gst_d3d12_dxgi_capture_do_capture (GstD3D12DxgiCapture * capture,
|
|||
GST_MINI_OBJECT_FLAG_SET (dmem, GST_D3D12_MEMORY_TRANSFER_NEED_DOWNLOAD);
|
||||
GST_MINI_OBJECT_FLAG_UNSET (dmem, GST_D3D12_MEMORY_TRANSFER_NEED_UPLOAD);
|
||||
|
||||
if (draw_mouse && !gst_d3d12_dxgi_capture_draw_mouse (self, buffer, crop_box)) {
|
||||
if (draw_mouse && !gst_d3d12_dxgi_capture_draw_mouse (self, buffer, crop_box,
|
||||
tex_desc.Format == DXGI_FORMAT_R16G16B16A16_UNORM)) {
|
||||
priv->WaitGPU ();
|
||||
priv->ctx = nullptr;
|
||||
return GST_FLOW_ERROR;
|
||||
|
|
|
@ -890,7 +890,8 @@ struct _GstD3D12GraphicsCapture
|
|||
static void gst_d3d12_graphics_capture_finalize (GObject * object);
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d12_graphics_capture_prepare (GstD3D12ScreenCapture * capture);
|
||||
gst_d3d12_graphics_capture_prepare (GstD3D12ScreenCapture * capture,
|
||||
guint flags);
|
||||
static gboolean
|
||||
gst_d3d12_graphics_capture_get_size (GstD3D12ScreenCapture * capture,
|
||||
guint * width, guint * height);
|
||||
|
@ -1162,7 +1163,8 @@ out:
|
|||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d12_graphics_capture_prepare (GstD3D12ScreenCapture * capture)
|
||||
gst_d3d12_graphics_capture_prepare (GstD3D12ScreenCapture * capture,
|
||||
guint flags)
|
||||
{
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
|
|
@ -49,14 +49,14 @@ gst_d3d12_screen_capture_init (GstD3D12ScreenCapture * self)
|
|||
}
|
||||
|
||||
GstFlowReturn
|
||||
gst_d3d12_screen_capture_prepare (GstD3D12ScreenCapture * capture)
|
||||
gst_d3d12_screen_capture_prepare (GstD3D12ScreenCapture * capture, guint flags)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_SCREEN_CAPTURE (capture), GST_FLOW_ERROR);
|
||||
|
||||
auto klass = GST_D3D12_SCREEN_CAPTURE_GET_CLASS (capture);
|
||||
g_assert (klass->prepare);
|
||||
|
||||
return klass->prepare (capture);
|
||||
return klass->prepare (capture, flags);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -73,6 +73,19 @@ gst_d3d12_screen_capture_get_size (GstD3D12ScreenCapture * capture,
|
|||
return klass->get_size (capture, width, height);
|
||||
}
|
||||
|
||||
GstVideoFormat
|
||||
gst_d3d12_screen_capture_get_format (GstD3D12ScreenCapture * capture)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_D3D12_SCREEN_CAPTURE (capture),
|
||||
GST_VIDEO_FORMAT_BGRA);
|
||||
|
||||
auto klass = GST_D3D12_SCREEN_CAPTURE_GET_CLASS (capture);
|
||||
if (klass->get_format)
|
||||
return klass->get_format (capture);
|
||||
|
||||
return GST_VIDEO_FORMAT_BGRA;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d12_screen_capture_unlock (GstD3D12ScreenCapture * capture)
|
||||
{
|
||||
|
|
|
@ -57,12 +57,15 @@ struct _GstD3D12ScreenCaptureClass
|
|||
{
|
||||
GstObjectClass parent_class;
|
||||
|
||||
GstFlowReturn (*prepare) (GstD3D12ScreenCapture * capture);
|
||||
GstFlowReturn (*prepare) (GstD3D12ScreenCapture * capture,
|
||||
guint flags);
|
||||
|
||||
gboolean (*get_size) (GstD3D12ScreenCapture * capture,
|
||||
guint * width,
|
||||
guint * height);
|
||||
|
||||
GstVideoFormat (*get_format) (GstD3D12ScreenCapture * capture);
|
||||
|
||||
gboolean (*unlock) (GstD3D12ScreenCapture * capture);
|
||||
|
||||
gboolean (*unlock_stop) (GstD3D12ScreenCapture * capture);
|
||||
|
@ -70,12 +73,15 @@ struct _GstD3D12ScreenCaptureClass
|
|||
|
||||
GType gst_d3d12_screen_capture_get_type (void);
|
||||
|
||||
GstFlowReturn gst_d3d12_screen_capture_prepare (GstD3D12ScreenCapture * capture);
|
||||
GstFlowReturn gst_d3d12_screen_capture_prepare (GstD3D12ScreenCapture * capture,
|
||||
guint flags);
|
||||
|
||||
gboolean gst_d3d12_screen_capture_get_size (GstD3D12ScreenCapture * capture,
|
||||
guint * width,
|
||||
guint * height);
|
||||
|
||||
GstVideoFormat gst_d3d12_screen_capture_get_format (GstD3D12ScreenCapture * capture);
|
||||
|
||||
gboolean gst_d3d12_screen_capture_unlock (GstD3D12ScreenCapture * capture);
|
||||
|
||||
gboolean gst_d3d12_screen_capture_unlock_stop (GstD3D12ScreenCapture * capture);
|
||||
|
|
|
@ -40,8 +40,9 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d12_screen_capture_debug);
|
|||
static GstStaticCaps template_caps =
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
|
||||
(GST_CAPS_FEATURE_MEMORY_D3D12_MEMORY,
|
||||
"BGRA") ", pixel-aspect-ratio = 1/1, colorimetry = (string) sRGB; "
|
||||
GST_VIDEO_CAPS_MAKE ("BGRA") ", pixel-aspect-ratio = 1/1, "
|
||||
"{ BGRA, RGBA64_LE }")
|
||||
", pixel-aspect-ratio = 1/1, colorimetry = (string) sRGB; "
|
||||
GST_VIDEO_CAPS_MAKE ("{ BGRA, RGBA64_LE }") ", pixel-aspect-ratio = 1/1, "
|
||||
"colorimetry = (string) sRGB");
|
||||
|
||||
enum
|
||||
|
|
|
@ -68,6 +68,7 @@ enum
|
|||
PROP_CAPTURE_API,
|
||||
PROP_ADAPTER,
|
||||
PROP_WINDOW_CAPTURE_MODE,
|
||||
PROP_TONEMAP,
|
||||
};
|
||||
|
||||
enum GstD3D12ScreenCaptureAPI
|
||||
|
@ -82,6 +83,12 @@ enum GstD3D12WindowCaptureMode
|
|||
GST_D3D12_WINDOW_CAPTURE_CLIENT,
|
||||
};
|
||||
|
||||
enum GstD3D12ScreenCaptureTonemap
|
||||
{
|
||||
GST_D3D12_SCREEN_CAPTURE_TONEMAP_LINEAR,
|
||||
GST_D3D12_SCREEN_CAPTURE_TONEMAP_REINHARD,
|
||||
};
|
||||
|
||||
#ifdef HAVE_WGC
|
||||
/**
|
||||
* GstD3D12ScreenCaptureAPI:
|
||||
|
@ -155,20 +162,58 @@ gst_d3d12_window_capture_mode_get_type (void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* GstD3D12ScreenCaptureTonemap:
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
#define GST_TYPE_D3D12_SCREEN_CAPTURE_TONEMAP (gst_d3d12_screen_capture_tonemap_get_type())
|
||||
static GType
|
||||
gst_d3d12_screen_capture_tonemap_get_type (void)
|
||||
{
|
||||
static GType type = 0;
|
||||
|
||||
GST_D3D12_CALL_ONCE_BEGIN {
|
||||
static const GEnumValue modes[] = {
|
||||
/**
|
||||
* GstD3D12ScreenCaptureTonemap::linear:
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
{GST_D3D12_SCREEN_CAPTURE_TONEMAP_LINEAR,
|
||||
"Linear scaling", "linear"},
|
||||
|
||||
/**
|
||||
* GstD3D12ScreenCaptureTonemap::reinhard:
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
{GST_D3D12_SCREEN_CAPTURE_TONEMAP_REINHARD, "Reinhard tonemap",
|
||||
"reinhard"},
|
||||
{0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
type = g_enum_register_static ("GstD3D12ScreenCaptureTonemap", modes);
|
||||
} GST_D3D12_CALL_ONCE_END;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
#define DEFAULT_MONITOR_INDEX -1
|
||||
#define DEFAULT_SHOW_CURSOR FALSE
|
||||
#define DEFAULT_SHOW_BORDER FALSE
|
||||
#define DEFAULT_CAPTURE_API GST_D3D12_SCREEN_CAPTURE_API_DXGI
|
||||
#define DEFAULT_ADAPTER -1
|
||||
#define DEFAULT_WINDOW_CAPTURE_MODE GST_D3D12_WINDOW_CAPTURE_DEFAULT
|
||||
#define DEFAULT_TONEMAP GST_D3D12_SCREEN_CAPTURE_TONEMAP_LINEAR
|
||||
|
||||
static GstStaticPadTemplate src_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
|
||||
(GST_CAPS_FEATURE_MEMORY_D3D12_MEMORY, "BGRA")
|
||||
(GST_CAPS_FEATURE_MEMORY_D3D12_MEMORY, "{ BGRA, RGBA64_LE }")
|
||||
", pixel-aspect-ratio = 1/1, colorimetry = (string) sRGB; "
|
||||
GST_VIDEO_CAPS_MAKE ("BGRA") ", pixel-aspect-ratio = 1/1, "
|
||||
"colorimetry = (string) sRGB"));
|
||||
GST_VIDEO_CAPS_MAKE ("{ BGRA, RGBA64_LE }")
|
||||
", pixel-aspect-ratio = 1/1, " "colorimetry = (string) sRGB"));
|
||||
|
||||
struct GstD3D12ScreenCaptureSrcPrivate
|
||||
{
|
||||
|
@ -203,6 +248,7 @@ struct GstD3D12ScreenCaptureSrcPrivate
|
|||
GstD3D12ScreenCaptureAPI capture_api = DEFAULT_CAPTURE_API;
|
||||
GstD3D12ScreenCaptureAPI selected_capture_api = DEFAULT_CAPTURE_API;
|
||||
GstD3D12WindowCaptureMode hwnd_capture_mode = DEFAULT_WINDOW_CAPTURE_MODE;
|
||||
GstD3D12ScreenCaptureTonemap tonemap = DEFAULT_TONEMAP;
|
||||
|
||||
gboolean flushing = FALSE;
|
||||
GstClockTime latency = GST_CLOCK_TIME_NONE;
|
||||
|
@ -388,6 +434,23 @@ gst_d3d12_screen_capture_src_class_init (GstD3D12ScreenCaptureSrcClass * klass)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* GstD3D12ScreenCaptureSrc:tonemap:
|
||||
*
|
||||
* Tonemapping method in case of HDR capture
|
||||
*
|
||||
* Since: 1.26
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_TONEMAP,
|
||||
g_param_spec_enum ("tonemap", "Tonemap",
|
||||
"Tonemapping method to use when HDR capturing is enabled",
|
||||
GST_TYPE_D3D12_SCREEN_CAPTURE_TONEMAP, DEFAULT_TONEMAP,
|
||||
(GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
|
||||
G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
gst_type_mark_as_plugin_api (GST_TYPE_D3D12_SCREEN_CAPTURE_TONEMAP,
|
||||
(GstPluginAPIFlags) 0);
|
||||
|
||||
element_class->provide_clock =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d12_screen_capture_src_provide_clock);
|
||||
element_class->set_context =
|
||||
|
@ -506,6 +569,9 @@ gst_d3d12_screen_capture_src_set_property (GObject * object, guint prop_id,
|
|||
}
|
||||
#endif
|
||||
break;
|
||||
case PROP_TONEMAP:
|
||||
priv->tonemap = (GstD3D12ScreenCaptureTonemap) g_value_get_enum (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -557,6 +623,9 @@ gst_d3d12_screen_capture_src_get_property (GObject * object, guint prop_id,
|
|||
case PROP_WINDOW_CAPTURE_MODE:
|
||||
g_value_set_enum (value, priv->hwnd_capture_mode);
|
||||
break;
|
||||
case PROP_TONEMAP:
|
||||
g_value_set_enum (value, priv->tonemap);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -622,6 +691,7 @@ gst_d3d12_screen_capture_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
|
|||
auto self = GST_D3D12_SCREEN_CAPTURE_SRC (bsrc);
|
||||
auto priv = self->priv;
|
||||
guint width, height;
|
||||
GstVideoFormat format = GST_VIDEO_FORMAT_BGRA;
|
||||
|
||||
std::lock_guard < std::recursive_mutex > lk (priv->lock);
|
||||
if (!priv->capture) {
|
||||
|
@ -637,10 +707,13 @@ gst_d3d12_screen_capture_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
|
|||
height = priv->crop_box.bottom - priv->crop_box.top;
|
||||
}
|
||||
|
||||
format = gst_d3d12_screen_capture_get_format (priv->capture);
|
||||
|
||||
auto caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (bsrc));
|
||||
caps = gst_caps_make_writable (caps);
|
||||
|
||||
gst_caps_set_simple (caps, "width", G_TYPE_INT, width, "height",
|
||||
gst_caps_set_simple (caps, "format", G_TYPE_STRING,
|
||||
gst_video_format_to_string (format), "width", G_TYPE_INT, width, "height",
|
||||
G_TYPE_INT, height, nullptr);
|
||||
|
||||
if (filter) {
|
||||
|
@ -920,7 +993,8 @@ gst_d3d12_screen_capture_src_start (GstBaseSrc * bsrc)
|
|||
}
|
||||
|
||||
/* Check if we can open device */
|
||||
ret = gst_d3d12_screen_capture_prepare (capture);
|
||||
ret = gst_d3d12_screen_capture_prepare (capture,
|
||||
priv->tonemap == GST_D3D12_SCREEN_CAPTURE_TONEMAP_REINHARD);
|
||||
switch (ret) {
|
||||
case GST_D3D12_SCREEN_CAPTURE_FLOW_EXPECTED_ERROR:
|
||||
case GST_FLOW_OK:
|
||||
|
|
Loading…
Reference in a new issue