mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 07:47:17 +00:00
d3d11screencapturesrc: Fix crash when d3d11 device is different from owned one
GstD3D11ScreenCapture object is pipeline-independent global object and the object can be shared by multiple src elements, in order to overcome a limitation of DXGI Desktop Duplication API. Note that the API allows only single capture session in a process for a monitor. Therefore GstD3D11ScreenCapture object must be able to handle a case where a src element holds different GstD3D11Device object. Which can happen when GstD3D11Device context is not shared by pipelines. What's changed: * Allocates capture texture with D3D11_RESOURCE_MISC_SHARED for the texture to be able to copied into other device's texture * Holds additional shader objects per src element and use it when drawing mouse Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1197 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2366>
This commit is contained in:
parent
b247305bfd
commit
e0a9a73adf
4 changed files with 285 additions and 51 deletions
|
@ -280,7 +280,8 @@ public:
|
||||||
texture_desc.BindFlags =
|
texture_desc.BindFlags =
|
||||||
D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
|
D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
|
||||||
texture_desc.CPUAccessFlags = 0;
|
texture_desc.CPUAccessFlags = 0;
|
||||||
texture_desc.MiscFlags = 0;
|
/* source element may hold different d3d11 device object */
|
||||||
|
texture_desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
|
||||||
|
|
||||||
hr = device_handle->CreateTexture2D (&texture_desc,
|
hr = device_handle->CreateTexture2D (&texture_desc,
|
||||||
nullptr, &shared_texture_);
|
nullptr, &shared_texture_);
|
||||||
|
@ -344,7 +345,11 @@ public:
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DrawMouse (ID3D11RenderTargetView * rtv, D3D11_BOX * cropBox)
|
bool
|
||||||
|
DrawMouse (GstD3D11Device * device, ID3D11RenderTargetView * rtv,
|
||||||
|
ID3D11VertexShader * vs, ID3D11PixelShader * ps,
|
||||||
|
ID3D11InputLayout * layout, ID3D11SamplerState * sampler,
|
||||||
|
ID3D11BlendState * blend, D3D11_BOX * cropBox)
|
||||||
{
|
{
|
||||||
GST_TRACE ("Drawing mouse");
|
GST_TRACE ("Drawing mouse");
|
||||||
|
|
||||||
|
@ -359,9 +364,9 @@ public:
|
||||||
D3D11_SUBRESOURCE_DATA InitData;
|
D3D11_SUBRESOURCE_DATA InitData;
|
||||||
D3D11_TEXTURE2D_DESC Desc;
|
D3D11_TEXTURE2D_DESC Desc;
|
||||||
D3D11_SHADER_RESOURCE_VIEW_DESC SDesc;
|
D3D11_SHADER_RESOURCE_VIEW_DESC SDesc;
|
||||||
ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device_);
|
ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
|
||||||
ID3D11DeviceContext *context_handle =
|
ID3D11DeviceContext *context_handle =
|
||||||
gst_d3d11_device_get_device_context_handle (device_);
|
gst_d3d11_device_get_device_context_handle (device);
|
||||||
|
|
||||||
VERTEX Vertices[NUMVERTICES] =
|
VERTEX Vertices[NUMVERTICES] =
|
||||||
{
|
{
|
||||||
|
@ -469,7 +474,7 @@ public:
|
||||||
|
|
||||||
// Create mouseshape as texture
|
// Create mouseshape as texture
|
||||||
HRESULT hr = device_handle->CreateTexture2D(&Desc, &InitData, &MouseTex);
|
HRESULT hr = device_handle->CreateTexture2D(&Desc, &InitData, &MouseTex);
|
||||||
if (!gst_d3d11_result (hr, device_)) {
|
if (!gst_d3d11_result (hr, device)) {
|
||||||
GST_ERROR ("Failed to create texture for rendering mouse");
|
GST_ERROR ("Failed to create texture for rendering mouse");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -477,7 +482,7 @@ public:
|
||||||
// Create shader resource from texture
|
// Create shader resource from texture
|
||||||
hr = device_handle->CreateShaderResourceView(MouseTex.Get(), &SDesc,
|
hr = device_handle->CreateShaderResourceView(MouseTex.Get(), &SDesc,
|
||||||
&ShaderRes);
|
&ShaderRes);
|
||||||
if (!gst_d3d11_result (hr, device_)) {
|
if (!gst_d3d11_result (hr, device)) {
|
||||||
GST_ERROR ("Failed to create shader resource view for rendering mouse");
|
GST_ERROR ("Failed to create shader resource view for rendering mouse");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -494,7 +499,7 @@ public:
|
||||||
|
|
||||||
// Create vertex buffer
|
// Create vertex buffer
|
||||||
hr = device_handle->CreateBuffer(&BDesc, &InitData, &VertexBufferMouse);
|
hr = device_handle->CreateBuffer(&BDesc, &InitData, &VertexBufferMouse);
|
||||||
if (!gst_d3d11_result (hr, device_)) {
|
if (!gst_d3d11_result (hr, device)) {
|
||||||
GST_ERROR ("Failed to create vertex buffer for rendering mouse");
|
GST_ERROR ("Failed to create vertex buffer for rendering mouse");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -502,19 +507,18 @@ public:
|
||||||
FLOAT BlendFactor[4] = {0.f, 0.f, 0.f, 0.f};
|
FLOAT BlendFactor[4] = {0.f, 0.f, 0.f, 0.f};
|
||||||
UINT Stride = sizeof(VERTEX);
|
UINT Stride = sizeof(VERTEX);
|
||||||
UINT Offset = 0;
|
UINT Offset = 0;
|
||||||
ID3D11SamplerState *samplers = sampler_.Get();
|
|
||||||
ID3D11ShaderResourceView *srv = ShaderRes.Get();
|
ID3D11ShaderResourceView *srv = ShaderRes.Get();
|
||||||
ID3D11Buffer *vert_buf = VertexBufferMouse.Get();
|
ID3D11Buffer *vert_buf = VertexBufferMouse.Get();
|
||||||
|
|
||||||
context_handle->IASetVertexBuffers(0, 1, &vert_buf, &Stride, &Offset);
|
context_handle->IASetVertexBuffers(0, 1, &vert_buf, &Stride, &Offset);
|
||||||
context_handle->OMSetBlendState(blend_.Get(), BlendFactor, 0xFFFFFFFF);
|
context_handle->OMSetBlendState(blend, BlendFactor, 0xFFFFFFFF);
|
||||||
context_handle->OMSetRenderTargets(1, &rtv, nullptr);
|
context_handle->OMSetRenderTargets(1, &rtv, nullptr);
|
||||||
context_handle->VSSetShader(vs_.Get(), nullptr, 0);
|
context_handle->VSSetShader(vs, nullptr, 0);
|
||||||
context_handle->PSSetShader(ps_.Get(), nullptr, 0);
|
context_handle->PSSetShader(ps, nullptr, 0);
|
||||||
context_handle->PSSetShaderResources(0, 1, &srv);
|
context_handle->PSSetShaderResources(0, 1, &srv);
|
||||||
context_handle->PSSetSamplers(0, 1, &samplers);
|
context_handle->PSSetSamplers(0, 1, &sampler);
|
||||||
context_handle->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
context_handle->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
context_handle->IASetInputLayout(layout_.Get());
|
context_handle->IASetInputLayout(layout);
|
||||||
|
|
||||||
D3D11_VIEWPORT VP;
|
D3D11_VIEWPORT VP;
|
||||||
VP.Width = static_cast<FLOAT>(FullDesc.Width);
|
VP.Width = static_cast<FLOAT>(FullDesc.Width);
|
||||||
|
@ -538,14 +542,61 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
GstFlowReturn
|
||||||
CopyToTexture (ID3D11Texture2D * texture, D3D11_BOX * cropBox)
|
CopyToTexture (GstD3D11Device * device, ID3D11Texture2D * texture,
|
||||||
|
D3D11_BOX * cropBox)
|
||||||
{
|
{
|
||||||
ID3D11DeviceContext *context_handle =
|
ID3D11DeviceContext *context_handle = nullptr;
|
||||||
gst_d3d11_device_get_device_context_handle (device_);
|
ComPtr <ID3D11Texture2D> tex;
|
||||||
|
ComPtr < ID3D11Query > query;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
context_handle = gst_d3d11_device_get_device_context_handle (device);
|
||||||
|
|
||||||
|
if (device == device_) {
|
||||||
|
tex = shared_texture_;
|
||||||
|
} else {
|
||||||
|
ID3D11Device *device_handle = nullptr;
|
||||||
|
ComPtr < IDXGIResource > dxgi_resource;
|
||||||
|
D3D11_QUERY_DESC query_desc;
|
||||||
|
HANDLE shared_handle;
|
||||||
|
|
||||||
|
device_handle = gst_d3d11_device_get_device_handle (device);
|
||||||
|
|
||||||
|
hr = shared_texture_.As (&dxgi_resource);
|
||||||
|
if (!gst_d3d11_result (hr, device_))
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
|
||||||
|
hr = dxgi_resource->GetSharedHandle (&shared_handle);
|
||||||
|
if (!gst_d3d11_result (hr, device_))
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
|
||||||
|
hr = device_handle->OpenSharedResource (shared_handle,
|
||||||
|
IID_PPV_ARGS (&tex));
|
||||||
|
if (!gst_d3d11_result (hr, device))
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
|
||||||
|
query_desc.Query = D3D11_QUERY_EVENT;
|
||||||
|
query_desc.MiscFlags = 0;
|
||||||
|
|
||||||
|
hr = device_handle->CreateQuery (&query_desc, &query);
|
||||||
|
if (!gst_d3d11_result (hr, device))
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
context_handle->CopySubresourceRegion (texture, 0, 0, 0, 0,
|
context_handle->CopySubresourceRegion (texture, 0, 0, 0, 0,
|
||||||
shared_texture_.Get(), 0, cropBox);
|
tex.Get(), 0, cropBox);
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
BOOL sync_done = FALSE;
|
||||||
|
|
||||||
|
do {
|
||||||
|
hr = context_handle->GetData (query.Get (),
|
||||||
|
&sync_done, sizeof (BOOL), 0);
|
||||||
|
} while (!sync_done && (hr == S_OK || hr == S_FALSE));
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -635,33 +686,11 @@ private:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For blending mouse pointer texture */
|
|
||||||
D3D11_BLEND_DESC blend_desc;
|
|
||||||
blend_desc.AlphaToCoverageEnable = FALSE;
|
|
||||||
blend_desc.IndependentBlendEnable = FALSE;
|
|
||||||
blend_desc.RenderTarget[0].BlendEnable = TRUE;
|
|
||||||
blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
|
||||||
blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
|
||||||
blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
|
||||||
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
|
||||||
blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
|
||||||
blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
|
||||||
blend_desc.RenderTarget[0].RenderTargetWriteMask =
|
|
||||||
D3D11_COLOR_WRITE_ENABLE_ALL;
|
|
||||||
|
|
||||||
ComPtr<ID3D11BlendState> blend;
|
|
||||||
hr = device_handle->CreateBlendState (&blend_desc, &blend);
|
|
||||||
if (!gst_d3d11_result (hr, device)) {
|
|
||||||
GST_ERROR ("Failed to create blend state, hr 0x%x", (guint) hr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Everything is prepared now */
|
/* Everything is prepared now */
|
||||||
vs_ = vs;
|
vs_ = vs;
|
||||||
ps_ = ps;
|
ps_ = ps;
|
||||||
layout_ = layout;
|
layout_ = layout;
|
||||||
sampler_ = sampler;
|
sampler_ = sampler;
|
||||||
blend_ = blend;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1452,7 +1481,6 @@ private:
|
||||||
ComPtr<ID3D11InputLayout> layout_;
|
ComPtr<ID3D11InputLayout> layout_;
|
||||||
ComPtr<ID3D11SamplerState> sampler_;
|
ComPtr<ID3D11SamplerState> sampler_;
|
||||||
ComPtr<IDXGIOutputDuplication> dupl_;
|
ComPtr<IDXGIOutputDuplication> dupl_;
|
||||||
ComPtr<ID3D11BlendState> blend_;
|
|
||||||
|
|
||||||
/* frame metadata */
|
/* frame metadata */
|
||||||
BYTE *metadata_buffer_;
|
BYTE *metadata_buffer_;
|
||||||
|
@ -1486,6 +1514,7 @@ struct _GstD3D11ScreenCapture
|
||||||
HMONITOR monitor_handle;
|
HMONITOR monitor_handle;
|
||||||
RECT desktop_coordinates;
|
RECT desktop_coordinates;
|
||||||
gboolean prepared;
|
gboolean prepared;
|
||||||
|
gint64 adapter_luid;
|
||||||
|
|
||||||
GRecMutex lock;
|
GRecMutex lock;
|
||||||
};
|
};
|
||||||
|
@ -1630,6 +1659,8 @@ gst_d3d11_screen_capture_constructed (GObject * object)
|
||||||
self->desktop_coordinates.right, self->desktop_coordinates.bottom,
|
self->desktop_coordinates.right, self->desktop_coordinates.bottom,
|
||||||
self->cached_width, self->cached_height);
|
self->cached_width, self->cached_height);
|
||||||
|
|
||||||
|
g_object_get (self->device, "adapter-luid", &self->adapter_luid, nullptr);
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -1805,15 +1836,33 @@ gst_d3d11_screen_capture_get_size (GstD3D11ScreenCapture * capture,
|
||||||
|
|
||||||
GstFlowReturn
|
GstFlowReturn
|
||||||
gst_d3d11_screen_capture_do_capture (GstD3D11ScreenCapture * capture,
|
gst_d3d11_screen_capture_do_capture (GstD3D11ScreenCapture * capture,
|
||||||
ID3D11Texture2D * texture, ID3D11RenderTargetView * rtv,
|
GstD3D11Device * device, ID3D11Texture2D * texture,
|
||||||
|
ID3D11RenderTargetView * rtv, ID3D11VertexShader * vs,
|
||||||
|
ID3D11PixelShader * ps, ID3D11InputLayout * layout,
|
||||||
|
ID3D11SamplerState * sampler, ID3D11BlendState * blend,
|
||||||
D3D11_BOX * crop_box, gboolean draw_mouse)
|
D3D11_BOX * crop_box, gboolean draw_mouse)
|
||||||
{
|
{
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
gboolean shared_device = FALSE;
|
||||||
guint width, height;
|
guint width, height;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_D3D11_SCREEN_CAPTURE (capture), GST_FLOW_ERROR);
|
g_return_val_if_fail (GST_IS_D3D11_SCREEN_CAPTURE (capture), GST_FLOW_ERROR);
|
||||||
g_return_val_if_fail (texture != nullptr, GST_FLOW_ERROR);
|
g_return_val_if_fail (texture != nullptr, GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
if (device != capture->device) {
|
||||||
|
gint64 luid;
|
||||||
|
|
||||||
|
g_object_get (device, "adapter-luid", &luid, nullptr);
|
||||||
|
/* source element must hold d3d11 device for the same GPU already
|
||||||
|
* by DXGI duplication API design */
|
||||||
|
if (luid != capture->adapter_luid) {
|
||||||
|
GST_ERROR_OBJECT (capture, "Trying to capture from different device");
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_device = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
g_rec_mutex_lock (&capture->lock);
|
g_rec_mutex_lock (&capture->lock);
|
||||||
if (!capture->prepared)
|
if (!capture->prepared)
|
||||||
ret = gst_d3d11_screen_capture_prepare (capture);
|
ret = gst_d3d11_screen_capture_prepare (capture);
|
||||||
|
@ -1858,14 +1907,26 @@ gst_d3d11_screen_capture_do_capture (GstD3D11ScreenCapture * capture,
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOG_OBJECT (capture, "Capture done");
|
GST_LOG_OBJECT (capture, "Capture done");
|
||||||
|
if (shared_device)
|
||||||
|
gst_d3d11_device_lock (device);
|
||||||
|
|
||||||
|
ret = capture->dupl_obj->CopyToTexture (device, texture, crop_box);
|
||||||
|
if (ret != GST_FLOW_OK)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (draw_mouse) {
|
||||||
|
capture->dupl_obj->DrawMouse (device,
|
||||||
|
rtv, vs, ps, layout, sampler, blend, crop_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (shared_device)
|
||||||
|
gst_d3d11_device_unlock (device);
|
||||||
|
|
||||||
capture->dupl_obj->CopyToTexture (texture, crop_box);
|
|
||||||
if (draw_mouse)
|
|
||||||
capture->dupl_obj->DrawMouse (rtv, crop_box);
|
|
||||||
gst_d3d11_device_unlock (capture->device);
|
gst_d3d11_device_unlock (capture->device);
|
||||||
g_rec_mutex_unlock (&capture->lock);
|
g_rec_mutex_unlock (&capture->lock);
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
|
|
|
@ -44,8 +44,14 @@ gboolean gst_d3d11_screen_capture_get_size (GstD3D11ScreenCapture * captu
|
||||||
guint * height);
|
guint * height);
|
||||||
|
|
||||||
GstFlowReturn gst_d3d11_screen_capture_do_capture (GstD3D11ScreenCapture * capture,
|
GstFlowReturn gst_d3d11_screen_capture_do_capture (GstD3D11ScreenCapture * capture,
|
||||||
|
GstD3D11Device * device,
|
||||||
ID3D11Texture2D * texture,
|
ID3D11Texture2D * texture,
|
||||||
ID3D11RenderTargetView * rtv,
|
ID3D11RenderTargetView * rtv,
|
||||||
|
ID3D11VertexShader * vs,
|
||||||
|
ID3D11PixelShader * ps,
|
||||||
|
ID3D11InputLayout * layout,
|
||||||
|
ID3D11SamplerState * sampler,
|
||||||
|
ID3D11BlendState * blend,
|
||||||
D3D11_BOX * crop_box,
|
D3D11_BOX * crop_box,
|
||||||
gboolean draw_mouse);
|
gboolean draw_mouse);
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "gstd3d11screencapturesrc.h"
|
#include "gstd3d11screencapturesrc.h"
|
||||||
#include "gstd3d11screencapture.h"
|
#include "gstd3d11screencapture.h"
|
||||||
#include "gstd3d11pluginutils.h"
|
#include "gstd3d11pluginutils.h"
|
||||||
|
#include "gstd3d11shader.h"
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -102,6 +103,12 @@ struct _GstD3D11ScreenCaptureSrc
|
||||||
GstClockTime max_latency;
|
GstClockTime max_latency;
|
||||||
|
|
||||||
gboolean downstream_supports_d3d11;
|
gboolean downstream_supports_d3d11;
|
||||||
|
|
||||||
|
ID3D11VertexShader *vs;
|
||||||
|
ID3D11PixelShader *ps;
|
||||||
|
ID3D11InputLayout *layout;
|
||||||
|
ID3D11SamplerState *sampler;
|
||||||
|
ID3D11BlendState *blend;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gst_d3d11_screen_capture_src_dispose (GObject * object);
|
static void gst_d3d11_screen_capture_src_dispose (GObject * object);
|
||||||
|
@ -599,6 +606,118 @@ error:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_d3d11_screen_capture_prepare_shader (GstD3D11ScreenCaptureSrc * self)
|
||||||
|
{
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
static const gchar vs_str[] =
|
||||||
|
"struct VS_INPUT {\n"
|
||||||
|
" float4 Position: POSITION;\n"
|
||||||
|
" float2 Texture: TEXCOORD;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct VS_OUTPUT {\n"
|
||||||
|
" float4 Position: SV_POSITION;\n"
|
||||||
|
" float2 Texture: TEXCOORD;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"VS_OUTPUT main (VS_INPUT input)\n"
|
||||||
|
"{\n"
|
||||||
|
" return input;\n"
|
||||||
|
"}";
|
||||||
|
static const gchar ps_str[] =
|
||||||
|
"Texture2D shaderTexture;\n"
|
||||||
|
"SamplerState samplerState;\n"
|
||||||
|
"\n"
|
||||||
|
"struct PS_INPUT {\n"
|
||||||
|
" float4 Position: SV_POSITION;\n"
|
||||||
|
" float2 Texture: TEXCOORD;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"struct PS_OUTPUT {\n"
|
||||||
|
" float4 Plane: SV_Target;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"PS_OUTPUT main(PS_INPUT input)\n"
|
||||||
|
"{\n"
|
||||||
|
" PS_OUTPUT output;\n"
|
||||||
|
" output.Plane = shaderTexture.Sample(samplerState, input.Texture);\n"
|
||||||
|
" return output;\n"
|
||||||
|
"}";
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
D3D11_INPUT_ELEMENT_DESC input_desc[] = {
|
||||||
|
{"POSITION",
|
||||||
|
0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||||
|
{"TEXCOORD",
|
||||||
|
0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
|
||||||
|
};
|
||||||
|
ComPtr < ID3D11VertexShader > vs;
|
||||||
|
ComPtr < ID3D11InputLayout > layout;
|
||||||
|
ComPtr < ID3D11PixelShader > ps;
|
||||||
|
ComPtr < ID3D11SamplerState > sampler;
|
||||||
|
ComPtr < ID3D11BlendState > blend;
|
||||||
|
D3D11_SAMPLER_DESC sampler_desc;
|
||||||
|
D3D11_BLEND_DESC blend_desc;
|
||||||
|
ID3D11Device *device_handle;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
device_handle = gst_d3d11_device_get_device_handle (self->device);
|
||||||
|
|
||||||
|
if (!gst_d3d11_create_vertex_shader (self->device,
|
||||||
|
vs_str, input_desc, G_N_ELEMENTS (input_desc), &vs, &layout)) {
|
||||||
|
GST_ERROR_OBJECT (self, "Failed to create vertex shader");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_d3d11_create_pixel_shader (self->device, ps_str, &ps)) {
|
||||||
|
GST_ERROR_OBJECT (self, "Failed to create pixel shader");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (&sampler_desc, 0, sizeof (D3D11_SAMPLER_DESC));
|
||||||
|
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
|
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||||
|
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||||
|
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||||
|
sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||||
|
sampler_desc.MinLOD = 0;
|
||||||
|
sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||||
|
|
||||||
|
hr = device_handle->CreateSamplerState (&sampler_desc, &sampler);
|
||||||
|
if (!gst_d3d11_result (hr, self->device)) {
|
||||||
|
GST_ERROR_OBJECT (self,
|
||||||
|
"Failed to create sampler state, hr 0x%x", (guint) hr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
blend_desc.AlphaToCoverageEnable = FALSE;
|
||||||
|
blend_desc.IndependentBlendEnable = FALSE;
|
||||||
|
blend_desc.RenderTarget[0].BlendEnable = TRUE;
|
||||||
|
blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||||
|
blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||||
|
blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||||
|
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||||
|
blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||||
|
blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||||
|
blend_desc.RenderTarget[0].RenderTargetWriteMask =
|
||||||
|
D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||||
|
|
||||||
|
hr = device_handle->CreateBlendState (&blend_desc, &blend);
|
||||||
|
if (!gst_d3d11_result (hr, self->device)) {
|
||||||
|
GST_ERROR_OBJECT (self,
|
||||||
|
"Failed to create blend state, hr 0x%x", (guint) hr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->vs = vs.Detach ();
|
||||||
|
self->ps = ps.Detach ();
|
||||||
|
self->layout = layout.Detach ();
|
||||||
|
self->sampler = sampler.Detach ();
|
||||||
|
self->blend = blend.Detach ();
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_d3d11_screen_capture_src_start (GstBaseSrc * bsrc)
|
gst_d3d11_screen_capture_src_start (GstBaseSrc * bsrc)
|
||||||
{
|
{
|
||||||
|
@ -655,6 +774,9 @@ gst_d3d11_screen_capture_src_start (GstBaseSrc * bsrc)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!gst_d3d11_screen_capture_prepare_shader (self))
|
||||||
|
goto error;
|
||||||
|
|
||||||
self->last_frame_no = -1;
|
self->last_frame_no = -1;
|
||||||
self->min_latency = self->max_latency = GST_CLOCK_TIME_NONE;
|
self->min_latency = self->max_latency = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
@ -690,6 +812,12 @@ gst_d3d11_screen_capture_src_stop (GstBaseSrc * bsrc)
|
||||||
gst_clear_object (&self->pool);
|
gst_clear_object (&self->pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_D3D11_CLEAR_COM (self->vs);
|
||||||
|
GST_D3D11_CLEAR_COM (self->ps);
|
||||||
|
GST_D3D11_CLEAR_COM (self->layout);
|
||||||
|
GST_D3D11_CLEAR_COM (self->sampler);
|
||||||
|
GST_D3D11_CLEAR_COM (self->blend);
|
||||||
|
|
||||||
gst_clear_object (&self->capture);
|
gst_clear_object (&self->capture);
|
||||||
gst_clear_object (&self->device);
|
gst_clear_object (&self->device);
|
||||||
|
|
||||||
|
@ -916,9 +1044,9 @@ again:
|
||||||
|
|
||||||
texture = (ID3D11Texture2D *) info.data;
|
texture = (ID3D11Texture2D *) info.data;
|
||||||
before_capture = gst_clock_get_time (clock);
|
before_capture = gst_clock_get_time (clock);
|
||||||
ret =
|
ret = gst_d3d11_screen_capture_do_capture (self->capture, self->device,
|
||||||
gst_d3d11_screen_capture_do_capture (self->capture, texture, rtv,
|
texture, rtv, self->vs, self->ps, self->layout, self->sampler,
|
||||||
&self->crop_box, draw_mouse);
|
self->blend, &self->crop_box, draw_mouse);
|
||||||
gst_memory_unmap (mem, &info);
|
gst_memory_unmap (mem, &info);
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
|
|
|
@ -143,9 +143,12 @@ gint
|
||||||
main (gint argc, gchar ** argv)
|
main (gint argc, gchar ** argv)
|
||||||
{
|
{
|
||||||
GstElement *pipeline, *src, *queue, *sink;
|
GstElement *pipeline, *src, *queue, *sink;
|
||||||
|
GstElement *pipeline_1 = nullptr, *src_1, *queue_1, *sink_1;
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
gboolean show_devices = FALSE;
|
gboolean show_devices = FALSE;
|
||||||
|
gboolean multi_pipelines = FALSE;
|
||||||
|
gboolean show_cursor = FALSE;
|
||||||
gint64 hmonitor = 0;
|
gint64 hmonitor = 0;
|
||||||
gint monitor_index = -1;
|
gint monitor_index = -1;
|
||||||
GError *err = nullptr;
|
GError *err = nullptr;
|
||||||
|
@ -158,6 +161,10 @@ main (gint argc, gchar ** argv)
|
||||||
"Address of HMONITOR handle", nullptr},
|
"Address of HMONITOR handle", nullptr},
|
||||||
{"index", 0, 0, G_OPTION_ARG_INT, &monitor_index,
|
{"index", 0, 0, G_OPTION_ARG_INT, &monitor_index,
|
||||||
"Monitor index to capture (-1 for primary monitor)", nullptr},
|
"Monitor index to capture (-1 for primary monitor)", nullptr},
|
||||||
|
{"multi-pipelines", 0, 0, G_OPTION_ARG_NONE, &multi_pipelines,
|
||||||
|
"Run two separate pipelines for capturing a single monitor", nullptr},
|
||||||
|
{"show-cursor", 0, 0, G_OPTION_ARG_NONE, &show_cursor,
|
||||||
|
"Draw mouse cursor", nullptr},
|
||||||
{nullptr}
|
{nullptr}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -185,12 +192,25 @@ main (gint argc, gchar ** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
src = gst_device_create_element (device, nullptr);
|
src = gst_device_create_element (device, nullptr);
|
||||||
gst_object_unref (device);
|
|
||||||
if (!src) {
|
if (!src) {
|
||||||
g_warning ("Failed to create d3d11screencapture element");
|
g_warning ("Failed to create d3d11screencapture element");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_object_set (src, "show-cursor", show_cursor, nullptr);
|
||||||
|
|
||||||
|
if (multi_pipelines) {
|
||||||
|
src_1 = gst_device_create_element (device, nullptr);
|
||||||
|
if (!src_1) {
|
||||||
|
g_warning ("Failed to create second d3d11screencapture element");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_set (src_1, "show-cursor", show_cursor, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_object_unref (device);
|
||||||
|
|
||||||
loop = g_main_loop_new (nullptr, FALSE);
|
loop = g_main_loop_new (nullptr, FALSE);
|
||||||
pipeline = gst_pipeline_new (nullptr);
|
pipeline = gst_pipeline_new (nullptr);
|
||||||
|
|
||||||
|
@ -203,12 +223,31 @@ main (gint argc, gchar ** argv)
|
||||||
gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), (GstBusFunc) bus_msg, loop);
|
gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), (GstBusFunc) bus_msg, loop);
|
||||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
if (multi_pipelines) {
|
||||||
|
pipeline_1 = gst_pipeline_new (nullptr);
|
||||||
|
|
||||||
|
queue_1 = gst_element_factory_make ("queue", nullptr);
|
||||||
|
sink_1 = gst_element_factory_make ("d3d11videosink", nullptr);
|
||||||
|
|
||||||
|
gst_bin_add_many (GST_BIN (pipeline_1), src_1, queue_1, sink_1, nullptr);
|
||||||
|
gst_element_link_many (src_1, queue_1, sink_1, nullptr);
|
||||||
|
|
||||||
|
gst_bus_add_watch (GST_ELEMENT_BUS (pipeline_1), (GstBusFunc) bus_msg, loop);
|
||||||
|
gst_element_set_state (pipeline_1, GST_STATE_PLAYING);
|
||||||
|
}
|
||||||
|
|
||||||
g_main_loop_run (loop);
|
g_main_loop_run (loop);
|
||||||
|
|
||||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
gst_bus_remove_watch (GST_ELEMENT_BUS (pipeline));
|
gst_bus_remove_watch (GST_ELEMENT_BUS (pipeline));
|
||||||
|
|
||||||
gst_object_unref (pipeline);
|
gst_object_unref (pipeline);
|
||||||
|
|
||||||
|
if (multi_pipelines) {
|
||||||
|
gst_element_set_state (pipeline_1, GST_STATE_NULL);
|
||||||
|
gst_bus_remove_watch (GST_ELEMENT_BUS (pipeline));
|
||||||
|
gst_object_unref (pipeline_1);
|
||||||
|
}
|
||||||
|
|
||||||
g_main_loop_unref (loop);
|
g_main_loop_unref (loop);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue