23 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0A00
25 #define _WIN32_WINNT 0x0A00
28 #define WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION 0x130000
31 #define ____FIReference_1_boolean_INTERFACE_DEFINED__
39 #include <d3dcompiler.h>
40 #include <dispatcherqueue.h>
41 #include <windows.foundation.h>
42 #include <windows.graphics.capture.h>
43 #include <windows.graphics.capture.interop.h>
44 #include <windows.graphics.directx.direct3d11.h>
45 #if HAVE_IDIRECT3DDXGIINTERFACEACCESS
46 #include <windows.graphics.directx.direct3d11.interop.h>
68 #include <condition_variable>
74 #include <type_traits>
79 using namespace ABI::Windows::System;
80 using namespace ABI::Windows::Foundation;
81 using namespace ABI::Windows::Graphics::Capture;
82 using namespace ABI::Windows::Graphics::DirectX::Direct3D11;
84 using Microsoft::WRL::ComPtr;
85 using ABI::Windows::Graphics::SizeInt32;
86 using ABI::Windows::Foundation::TimeSpan;
87 using ABI::Windows::Graphics::DirectX::DirectXPixelFormat;
89 #define TIMESPAN_RES 10000000
90 #define TIMESPAN_RES64 INT64_C(10000000)
92 #define CAPTURE_POOL_SIZE 2
98 #define CCTX(ctx) static_cast<GfxCaptureContext*>(ctx)
104 HRESULT (WINAPI *RoInitialize)(RO_INIT_TYPE initType);
105 void (WINAPI *RoUninitialize)(void);
106 HRESULT (WINAPI *RoGetActivationFactory)(HSTRING activatableClassId, REFIID
iid,
void **factory);
107 HRESULT (WINAPI *WindowsCreateStringReference)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING *
string);
110 HRESULT (WINAPI *DwmGetWindowAttribute)(HWND hwnd, DWORD dwAttribute, PVOID
pvAttribute, DWORD cbAttribute);
113 HRESULT (WINAPI *CreateDirect3D11DeviceFromDXGIDevice)(IDXGIDevice *dxgiDevice, IInspectable **
graphicsDevice);
119 DPI_AWARENESS_CONTEXT (WINAPI *SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT dpiContext);
122 HRESULT (WINAPI *D3DCompile)(LPCVOID pSrcData, SIZE_T
SrcDataSize, LPCSTR pSourceName,
const D3D10_SHADER_MACRO *pDefines, ID3DInclude *pInclude,
123 LPCSTR pEntrypoint, LPCSTR
pTarget, UINT Flags1, UINT Flags2, ID3DBlob **ppCode, ID3DBlob **ppErrorMsgs);
136 EventRegistrationToken frame_arrived_token { 0 };
137 EventRegistrationToken closed_token { 0 };
141 std::atomic<bool> window_closed {
false };
142 std::atomic<uint64_t> frame_seq { 0 };
144 SizeInt32 cap_size { 0, 0 };
145 RECT client_area_offsets { 0, 0, 0, 0 };
158 std::unique_ptr<GfxCaptureContextWgc>
wgc;
159 std::unique_ptr<GfxCaptureContextD3D>
d3d;
162 bool wgc_thread_created {
false };
163 DWORD wgc_thread_id { 0 };
166 volatile int wgc_thread_init_res { INT_MAX };
169 HWND capture_hwnd {
nullptr };
170 HMONITOR capture_hmonitor {
nullptr };
184 template <
typename T>
186 HSTRING_HEADER hsheader = { 0 };
189 HRESULT hr =
ctx->fn.WindowsCreateStringReference(clsid, (UINT32)wcslen(clsid), &hsheader, &hs);
193 return ctx->fn.RoGetActivationFactory(hs, IID_PPV_ARGS(factory));
196 #define CHECK_HR(fcall, action) \
198 HRESULT fhr = fcall; \
200 av_log(avctx, AV_LOG_ERROR, #fcall " failed: 0x%08lX\n", fhr); \
204 #define CHECK_HR_RET(...) CHECK_HR((__VA_ARGS__), return AVERROR_EXTERNAL)
205 #define CHECK_HR_FAIL(...) CHECK_HR((__VA_ARGS__), ret = AVERROR_EXTERNAL; goto fail)
206 #define CHECK_HR_LOG(...) CHECK_HR((__VA_ARGS__), (void)0)
214 wgctx->frame_seq.fetch_add(1, std::memory_order_release);
215 wgctx->frame_arrived_cond.notify_one();
219 wgctx->window_closed.store(
true, std::memory_order_release);
220 wgctx->frame_arrived_cond.notify_one();
227 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
229 if (wgctx->closed_token.value && wgctx->capture_item) {
230 CHECK_HR_LOG(wgctx->capture_item->remove_Closed(wgctx->closed_token));
231 wgctx->closed_token.value = 0;
234 if (wgctx->frame_arrived_token.value && wgctx->frame_pool) {
235 CHECK_HR_LOG(wgctx->frame_pool->remove_FrameArrived(wgctx->frame_arrived_token));
236 wgctx->frame_arrived_token.value = 0;
239 if (wgctx->capture_session) {
240 ComPtr<IClosable> closable;
241 if (SUCCEEDED(wgctx->capture_session.As(&closable))) {
248 if (wgctx->frame_pool) {
249 ComPtr<IClosable> closable;
250 if (SUCCEEDED(wgctx->frame_pool.As(&closable))) {
262 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
264 if (!
ctx->capture_hwnd) {
265 wgctx->client_area_offsets.left = 0;
266 wgctx->client_area_offsets.top = 0;
267 wgctx->client_area_offsets.right = 0;
268 wgctx->client_area_offsets.bottom = 0;
272 RECT client_rect = {};
273 RECT frame_bounds = {};
274 RECT window_rect = {};
276 if (IsIconic(
ctx->capture_hwnd)) {
281 if (!GetClientRect(
ctx->capture_hwnd, &client_rect)) {
286 if (!MapWindowPoints(
ctx->capture_hwnd,
nullptr, (POINT*)&client_rect, 2)) {
291 if (FAILED(
ctx->fn.DwmGetWindowAttribute(
ctx->capture_hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frame_bounds,
sizeof(window_rect))))
294 if (!GetWindowRect(
ctx->capture_hwnd, &window_rect))
297 if (wgctx->cap_size.Width == frame_bounds.right - frame_bounds.left ||
298 wgctx->cap_size.Height == frame_bounds.bottom - frame_bounds.top) {
300 }
else if (wgctx->cap_size.Width == window_rect.right - window_rect.left ||
301 wgctx->cap_size.Height == window_rect.bottom - window_rect.top) {
303 frame_bounds = window_rect;
305 if ((frame_bounds.top == frame_bounds.bottom || frame_bounds.left == frame_bounds.right) &&
306 (window_rect.top == window_rect.bottom || window_rect.left == window_rect.right))
311 av_log(avctx,
AV_LOG_VERBOSE,
"Failed to get valid window rect, client area may be inaccurate\n");
315 wgctx->client_area_offsets.left =
FFMAX(client_rect.left - frame_bounds.left, 0);
316 wgctx->client_area_offsets.top =
FFMAX(client_rect.top - frame_bounds.top, 0);
317 wgctx->client_area_offsets.right =
FFMAX(frame_bounds.right - client_rect.right, 0);
318 wgctx->client_area_offsets.bottom =
FFMAX(frame_bounds.bottom - client_rect.bottom, 0);
320 av_log(avctx,
AV_LOG_DEBUG,
"Client area offsets: left=%ld top=%ld right=%ld bottom=%ld\n",
321 wgctx->client_area_offsets.left, wgctx->client_area_offsets.top,
322 wgctx->client_area_offsets.right, wgctx->client_area_offsets.bottom);
331 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
334 ComPtr<IDirect3D11CaptureFramePoolStatics> frame_pool_statics;
335 ComPtr<ID3D11Device> d3d11_device =
ctx->device_hwctx->device;
336 ComPtr<ID3D10Multithread> d3d10_multithread;
337 ComPtr<IDXGIDevice> dxgi_device;
338 ComPtr<IGraphicsCaptureSession2> session2;
339 ComPtr<IGraphicsCaptureSession3> session3;
340 ComPtr<IGraphicsCaptureSession5> session5;
342 DirectXPixelFormat fmt = DirectXPixelFormat::DirectXPixelFormat_B8G8R8A8UIntNormalized;
344 fmt = DirectXPixelFormat::DirectXPixelFormat_R16G16B16A16Float;
346 CHECK_HR_RET(wgctx->capture_item->get_Size(&wgctx->cap_size));
352 d3d10_multithread->SetMultithreadProtected(TRUE);
355 CHECK_HR_RET(
ctx->fn.CreateDirect3D11DeviceFromDXGIDevice(dxgi_device.Get(), &wgctx->d3d_device));
357 CHECK_HR_RET(get_activation_factory<IDirect3D11CaptureFramePoolStatics>(
ctx, RuntimeClass_Windows_Graphics_Capture_Direct3D11CaptureFramePool, &frame_pool_statics));
359 CHECK_HR_RET(wgctx->frame_pool->CreateCaptureSession(wgctx->capture_item.Get(), &wgctx->capture_session));
361 if (SUCCEEDED(wgctx->capture_session.As(&session2))) {
362 if (FAILED(session2->put_IsCursorCaptureEnabled(cctx->
capture_cursor))) {
369 if (SUCCEEDED(wgctx->capture_session.As(&session3))) {
371 if (FAILED(session3->put_IsBorderRequired(cctx->
display_border))) {
378 if (SUCCEEDED(wgctx->capture_session.As(&session5))) {
380 if (FAILED(session5->put_MinUpdateInterval(ivl))) {
381 av_log(avctx,
AV_LOG_WARNING,
"Failed setting minimum update interval, framerate may be limited\n");
384 av_log(avctx,
AV_LOG_WARNING,
"Setting minimum update interval unavailable, framerate may be limited\n");
387 wgctx->window_closed = 0;
390 create_cb_handler<ITypedEventHandler<GraphicsCaptureItem*,IInspectable*>, IGraphicsCaptureItem*, IInspectable*>(
391 [avctx,
ctx](
auto,
auto) {
392 av_log(avctx, AV_LOG_INFO,
"Capture item closed\n");
393 wgc_closed_handler(ctx->wgc);
395 }).Get(), &wgctx->closed_token));
398 create_cb_handler<ITypedEventHandler<Direct3D11CaptureFramePool*,IInspectable*>, IDirect3D11CaptureFramePool*, IInspectable*>(
399 [avctx,
ctx](
auto,
auto) {
400 av_log(avctx, AV_LOG_TRACE,
"Frame arrived\n");
401 wgc_frame_arrived_handler(ctx->wgc);
403 }).Get(), &wgctx->frame_arrived_token));
412 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
416 ComPtr<IGraphicsCaptureItemInterop> capture_item_interop;
417 CHECK_HR_RET(get_activation_factory<IGraphicsCaptureItemInterop>(
ctx, RuntimeClass_Windows_Graphics_Capture_GraphicsCaptureItem, &capture_item_interop));
419 if (
ctx->capture_hmonitor) {
420 hr = capture_item_interop->CreateForMonitor(
ctx->capture_hmonitor, IID_PPV_ARGS(&wgctx->capture_item));
422 av_log(avctx,
AV_LOG_ERROR,
"Failed to setup graphics capture for monitor (0x%08lX)\n", hr);
425 }
else if (
ctx->capture_hwnd) {
426 hr = capture_item_interop->CreateForWindow(
ctx->capture_hwnd, IID_PPV_ARGS(&wgctx->capture_item));
428 av_log(avctx,
AV_LOG_ERROR,
"Failed to setup graphics capture for window (0x%08lX)\n", hr);
439 hr =
ctx->wgc->capture_session->StartCapture();
441 av_log(avctx,
AV_LOG_ERROR,
"Failed to start graphics capture session (0x%08lX)\n", hr);
452 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
454 ComPtr<IDirect3DSurface> capture_surface;
455 ComPtr<IDirect3DDxgiInterfaceAccess> dxgi_interface_access;
456 ComPtr<ID3D11Texture2D> frame_texture;
459 CHECK_HR_RET(wgctx->frame_pool->TryGetNextFrame(capture_frame->ReleaseAndGetAddressOf()));
460 if (!capture_frame->Get())
467 DirectXPixelFormat fmt = DirectXPixelFormat::DirectXPixelFormat_B8G8R8A8UIntNormalized;
469 fmt = DirectXPixelFormat::DirectXPixelFormat_R16G16B16A16Float;
486 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
490 PeekMessage(&msg,
nullptr, 0, 0, PM_NOREMOVE);
492 DispatcherQueueOptions
options = { 0 };
493 options.dwSize =
sizeof(DispatcherQueueOptions);
494 options.threadType = DISPATCHERQUEUE_THREAD_TYPE::DQTYPE_THREAD_CURRENT;
495 options.apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE::DQTAT_COM_NONE;
498 CHECK_HR_RET(wgctx->dispatcher_queue_controller->get_DispatcherQueue(&wgctx->dispatcher_queue));
511 ctx->fn.RoUninitialize();
521 ctx->wgc = std::make_unique<GfxCaptureContextWgc>();
523 ctx->fn.SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
525 hr =
ctx->fn.RoInitialize(RO_INIT_MULTITHREADED);
555 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
556 ComPtr<IAsyncAction> async;
561 while (BOOL res = GetMessage(&msg,
NULL, 0, 0)) {
569 if (FAILED(wgctx->dispatcher_queue_controller->ShutdownQueueAsync(&async))) {
573 async->put_Completed(create_cb_handler<IAsyncActionCompletedHandler, IAsyncAction*, AsyncStatus>(
575 PostThreadMessage(
ctx->wgc_thread_id, WM_QUIT, 0, 0);
584 TranslateMessage(&msg);
585 DispatchMessage(&msg);
589 av_log(avctx,
AV_LOG_ERROR,
"WGC Thread message loop ended without proper shutdown\n");
605 static const char name_prefix[] =
"wgc_winrt@0x";
606 char thread_name[
sizeof(name_prefix) +
sizeof(
void*) * 2];
607 snprintf(thread_name,
sizeof(thread_name),
"%s%" PRIxPTR, name_prefix, (uintptr_t)avctx);
610 std::lock_guard init_lock(
ctx->wgc_thread_init_mutex);
611 ctx->wgc_thread_id = GetCurrentThreadId();
615 }
catch (
const std::bad_alloc &) {
617 }
catch (
const std::exception &e) {
618 av_log(avctx,
AV_LOG_ERROR,
"unhandled exception in WGC thread init: %s\n", e.what());
625 ctx->wgc_thread_init_cond.notify_all();
626 if (
ctx->wgc_thread_init_res < 0)
627 return (
void*)(intptr_t)
AVERROR(ENOSYS);
634 }
catch (
const std::bad_alloc &) {
636 }
catch (
const std::exception &e) {
637 av_log(avctx,
AV_LOG_ERROR,
"unhandled exception in WGC thread worker: %s\n", e.what());
644 std::lock_guard uninit_lock(
ctx->wgc_thread_uninit_mutex);
647 return (
void*)(intptr_t)
ret;
660 if (
ctx->wgc_thread_created) {
664 void *wgc_res =
nullptr;
666 ret = (int)(intptr_t)wgc_res;
668 ctx->wgc_thread_id = 0;
669 ctx->wgc_thread_created =
false;
680 if (
ctx->wgc_thread_created ||
ctx->wgc_thread_id) {
685 std::unique_lock wgc_lock(
ctx->wgc_thread_init_mutex);
686 ctx->wgc_thread_init_res = INT_MAX;
694 ctx->wgc_thread_created =
true;
696 if (!
ctx->wgc_thread_init_cond.wait_for(wgc_lock, std::chrono::seconds(1), [&]() {
697 return ctx->wgc_thread_init_res != INT_MAX;
703 return ctx->wgc_thread_init_res;
706 template <
typename F>
711 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
713 std::lock_guard uninit_lock(
ctx->wgc_thread_uninit_mutex);
721 std::condition_variable
cond;
722 std::atomic<bool> done {
false };
723 std::atomic<bool> cancel {
false };
726 auto cbdata = std::make_shared<CBData>();
728 std::unique_lock cblock(cbdata->mutex);
732 create_cb_handler<IDispatcherQueueHandler>(
733 [
cb = std::forward<F>(
cb), cbdata]() {
735 std::lock_guard lock(cbdata->mutex);
736 if (cbdata->cancel.load(std::memory_order_acquire))
741 } catch (const std::bad_alloc &) {
742 cbdata->ret = AVERROR(ENOMEM);
744 cbdata->ret = AVERROR_BUG;
747 cbdata->done.store(true, std::memory_order_release);
750 cbdata->cond.notify_one();
758 if (!cbdata->cond.wait_for(cblock, std::chrono::seconds(1), [&]() { return cbdata->done.load(std::memory_order_acquire); })) {
759 cbdata->cancel.store(
true, std::memory_order_release);
776 std::string pat(pattern);
778 auto flags = std::regex::ECMAScript | std::regex::optimize;
779 if (pat.rfind(
"(?i)", 0) == 0 || pat.rfind(
"(?I)", 0) == 0) {
781 flags |= std::regex::icase;
782 }
else if(pat.rfind(
"(?c)", 0) == 0 || pat.rfind(
"(?C)", 0) == 0) {
788 }
catch (
const std::regex_error &e) {
789 av_log(avctx,
AV_LOG_ERROR,
"Failed to compile regex '%s': %s\n", pat.c_str(), e.what());
800 int utf8size = WideCharToMultiByte(CP_UTF8, 0, in, -1,
nullptr, 0,
nullptr,
nullptr);
805 out->resize(utf8size - 1);
807 if (WideCharToMultiByte(CP_UTF8, 0, in, -1,
out->data(), utf8size,
nullptr,
nullptr) != utf8size)
818 if (!GetWindowThreadProcessId(hwnd, &pid))
821 handle_ptr_t proc(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid));
825 std::wstring image_name;
826 DWORD image_name_size = 512;
829 DWORD
len = image_name_size;
830 image_name.resize(
len);
831 if (QueryFullProcessImageNameW(proc.get(), 0, image_name.data(), &
len)) {
832 image_name.resize(
len);
835 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
836 image_name_size *= 2;
842 if (image_name.empty())
845 const wchar_t *
base = image_name.c_str();
846 size_t pos = image_name.find_last_of(
L"\\/");
847 if (
pos != std::string::npos)
871 av_log(avctx, AV_LOG_DEBUG,
"Found capture monitor: %d\n", cctx->monitor_idx);
872 ctx->capture_hmonitor = hmonitor;
877 if (EnumDisplayMonitors(
NULL,
NULL,
cb->proc,
cb->lparam) || !
ctx->capture_hmonitor)
881 std::regex text_regex;
885 std::regex class_regex;
889 std::regex exe_regex;
893 std::string window_text;
894 std::wstring window_text_w;
895 std::string window_class;
896 std::wstring window_class_w;
897 std::string window_exe;
900 if (!GetWindowRect(hwnd, &
r) ||
r.right <=
r.left ||
r.bottom <=
r.top || !IsWindowVisible(hwnd))
903 window_text_w.resize(GetWindowTextLengthW(hwnd) + 1);
904 int len = GetWindowTextW(hwnd, window_text_w.data(), (
int)window_text_w.size());
906 window_text_w.resize(
len);
913 window_class_w.resize(256);
914 len = GetClassNameW(hwnd, window_class_w.data(), (
int)window_class_w.size());
916 window_class_w.resize(
len);
918 window_class.clear();
920 window_class.clear();
926 hwnd, window_text.c_str(), window_class.c_str(), window_exe.c_str());
929 if (window_text.empty() || !std::regex_search(window_text, text_regex))
934 if (window_class.empty() || !std::regex_search(window_class, class_regex))
939 if (window_exe.empty() || !std::regex_search(window_exe, exe_regex))
944 window_text.c_str(), window_class.c_str(), window_exe.c_str());
945 ctx->capture_hwnd = hwnd;
948 if (EnumWindows(
cb->proc,
cb->lparam) || !
ctx->capture_hwnd)
952 ctx->capture_hmonitor = MonitorFromWindow(
ctx->capture_hwnd, MONITOR_DEFAULTTONEAREST);
954 if (!
ctx->capture_hmonitor) {
988 *
out =
reinterpret_cast<T>(GetProcAddress(hModule.get(), lpProcName));
996 #define LOAD_DLL(handle, name) \
997 handle = hmodule_ptr_t(LoadLibraryExW(L##name, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)); \
999 av_log(avctx, AV_LOG_ERROR, "Failed opening " #name "\n"); \
1000 return AVERROR(ENOSYS); \
1003 #define LOAD_FUNC(handle, name) \
1004 GetProcAddressTyped(handle, #name, &ctx->fn.name); \
1005 if (!ctx->fn.name) { \
1006 av_log(avctx, AV_LOG_ERROR, "Failed loading " #name "\n"); \
1007 return AVERROR(ENOSYS); \
1011 LOAD_DLL(
ctx->fn.graphicscapture_handle,
"graphicscapture.dll");
1016 LOAD_DLL(
ctx->fn.coremsg_handle,
"coremessaging.dll");
1018 LOAD_DLL(
ctx->fn.d3dcompiler_handle,
"d3dcompiler_47.dll");
1022 LOAD_FUNC(
ctx->fn.combase_handle, RoGetActivationFactory);
1023 LOAD_FUNC(
ctx->fn.combase_handle, WindowsCreateStringReference);
1025 LOAD_FUNC(
ctx->fn.dwmapi_handle, DwmGetWindowAttribute);
1027 LOAD_FUNC(
ctx->fn.d3d11_handle, CreateDirect3D11DeviceFromDXGIDevice);
1029 LOAD_FUNC(
ctx->fn.coremsg_handle, CreateDispatcherQueueController);
1031 LOAD_FUNC(
ctx->fn.user32_handle, SetThreadDpiAwarenessContext);
1046 ctx->d3d = std::make_unique<GfxCaptureContextD3D>();
1050 ctx->fn.RoUninitialize =
nullptr;
1068 if (!
ctx->frames_ref)
1080 ctx->frames_hwctx->BindFlags = D3D11_BIND_RENDER_TARGET;
1098 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
1119 cap_w -= wgctx->client_area_offsets.left + wgctx->client_area_offsets.right;
1120 cap_h -= wgctx->client_area_offsets.top + wgctx->client_area_offsets.bottom;
1140 std::unique_ptr<GfxCaptureContextD3D> &d3dctx =
ctx->d3d;
1143 ComPtr<ID3DBlob> vs_blob, ps_blob, err_blob;
1144 CD3D11_SAMPLER_DESC sampler_desc(CD3D11_DEFAULT{});
1145 UINT
flags = D3DCOMPILE_OPTIMIZATION_LEVEL3;
1147 hr =
ctx->fn.D3DCompile(
render_shader_src,
sizeof(
render_shader_src) - 1,
NULL,
NULL,
NULL,
"main_vs",
"vs_4_0",
flags, 0, &vs_blob, &err_blob);
1150 av_log(avctx,
AV_LOG_ERROR,
"Failed compiling vertex shader: %.*s\n", (
int)err_blob->GetBufferSize(), (
char*)err_blob->GetBufferPointer());
1157 const char *ps_entry =
"main_ps_bicubic";
1159 ps_entry =
"main_ps";
1160 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
1163 hr =
ctx->fn.D3DCompile(
render_shader_src,
sizeof(
render_shader_src) - 1,
NULL,
NULL,
NULL, ps_entry,
"ps_4_0",
flags, 0, &ps_blob, &err_blob);
1166 av_log(avctx,
AV_LOG_ERROR,
"Failed compiling pixel shader: %.*s\n", (
int)err_blob->GetBufferSize(), (
char*)err_blob->GetBufferPointer());
1173 CHECK_HR_RET(
ctx->device_hwctx->device->CreateVertexShader(vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(),
NULL, &d3dctx->vertex_shader));
1174 CHECK_HR_RET(
ctx->device_hwctx->device->CreatePixelShader(ps_blob->GetBufferPointer(), ps_blob->GetBufferSize(),
NULL, &d3dctx->pixel_shader));
1176 CHECK_HR_RET(
ctx->device_hwctx->device->CreateSamplerState(&sampler_desc, &d3dctx->sampler_state));
1178 D3D11_BUFFER_DESC cb_desc = { 0 };
1179 cb_desc.ByteWidth = 48;
1180 cb_desc.Usage = D3D11_USAGE_DYNAMIC;
1181 cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
1182 cb_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1184 CHECK_HR_RET(
ctx->device_hwctx->device->CreateBuffer(&cb_desc,
NULL, &d3dctx->shader_cb));
1186 CHECK_HR_RET(
ctx->device_hwctx->device->CreateDeferredContext(0, &d3dctx->deferred_ctx));
1209 if (!
ctx->device_ref)
1247 std::lock_guard wgc_lock(
ctx->wgc_thread_uninit_mutex);
1253 outlink->
w =
ctx->frames_ctx->width;
1254 outlink->
h =
ctx->frames_ctx->height;
1268 std::unique_ptr<GfxCaptureContextD3D> &d3dctx =
ctx->d3d;
1269 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
1272 ID3D11DeviceContext *dev_ctx =
ctx->device_hwctx->device_context;
1273 ComPtr<ID3D11DeviceContext> &def_ctx = d3dctx->deferred_ctx;
1275 D3D11_TEXTURE2D_DESC dst_tex_desc;
1276 reinterpret_cast<ID3D11Texture2D*
>(
frame->data[0])->GetDesc(&dst_tex_desc);
1278 D3D11_TEXTURE2D_DESC src_tex_desc;
1279 src_tex->GetDesc(&src_tex_desc);
1281 D3D11_RENDER_TARGET_VIEW_DESC target_desc = {};
1282 target_desc.Format = dst_tex_desc.Format;
1284 if (dst_tex_desc.ArraySize > 1) {
1285 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
1286 target_desc.Texture2DArray.ArraySize = 1;
1287 target_desc.Texture2DArray.FirstArraySlice = (uintptr_t)
frame->data[1];
1288 target_desc.Texture2DArray.MipSlice = 0;
1290 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
1291 target_desc.Texture2D.MipSlice = 0;
1294 ComPtr<ID3D11RenderTargetView> rtv;
1296 reinterpret_cast<ID3D11Resource*
>(
frame->data[0]), &target_desc, &rtv));
1298 ComPtr<ID3D11ShaderResourceView> srv;
1299 CHECK_HR_RET(dev->CreateShaderResourceView(src_tex.Get(),
nullptr, &srv));
1307 crop_left += wgctx->client_area_offsets.left;
1308 crop_top += wgctx->client_area_offsets.top;
1309 crop_right += wgctx->client_area_offsets.right;
1310 crop_bottom += wgctx->client_area_offsets.bottom;
1319 int cropped_w = wgctx->cap_size.Width - crop_left - crop_right;
1320 int cropped_h = wgctx->cap_size.Height - crop_top - crop_bottom;
1322 D3D11_VIEWPORT viewport = { 0 };
1323 viewport.MinDepth = 0.f;
1324 viewport.MaxDepth = 1.f;
1328 viewport.Width = (
float)cropped_w;
1329 viewport.Height = (
float)cropped_h;
1332 viewport.Width = dst_tex_desc.Width;
1333 viewport.Height = dst_tex_desc.Height;
1336 float scale =
FFMIN(dst_tex_desc.Width / (
float)cropped_w,
1337 dst_tex_desc.Height / (
float)cropped_h);
1338 viewport.Width = cropped_w *
scale;
1339 viewport.Height = cropped_h *
scale;
1347 def_ctx->RSSetViewports(1, &viewport);
1349 D3D11_MAPPED_SUBRESOURCE
map;
1350 CHECK_HR_RET(def_ctx->Map(d3dctx->shader_cb.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &
map));
1352 float *cb_f =
static_cast<float*
>(
map.pData);
1353 uint32_t *cb_u =
static_cast<uint32_t*
>(
map.pData);
1354 cb_f[0] = (
float)cropped_w;
1355 cb_f[1] = (
float)cropped_h;
1356 cb_f[2] = viewport.Width;
1357 cb_f[3] = viewport.Height;
1358 cb_f[4] = crop_left / (
float)src_tex_desc.Width;
1359 cb_f[5] = crop_top / (
float)src_tex_desc.Height;
1360 cb_f[6] = (crop_left + cropped_w) / (
float)src_tex_desc.Width;
1361 cb_f[7] = (crop_top + cropped_h) / (
float)src_tex_desc.Height;
1366 def_ctx->Unmap(d3dctx->shader_cb.Get(), 0);
1368 def_ctx->OMSetRenderTargets(1, rtv.GetAddressOf(),
nullptr);
1370 const float clear_color[4] = {0.f, 0.f, 0.f, 1.f};
1371 def_ctx->ClearRenderTargetView(rtv.Get(), clear_color);
1373 def_ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1374 def_ctx->VSSetShader(d3dctx->vertex_shader.Get(),
nullptr, 0);
1375 def_ctx->VSSetConstantBuffers(0, 1, d3dctx->shader_cb.GetAddressOf());
1376 def_ctx->PSSetShader(d3dctx->pixel_shader.Get(),
nullptr, 0);
1377 def_ctx->PSSetSamplers(0, 1, d3dctx->sampler_state.GetAddressOf());
1378 def_ctx->PSSetShaderResources(0, 1, srv.GetAddressOf());
1379 def_ctx->PSSetConstantBuffers(0, 1, d3dctx->shader_cb.GetAddressOf());
1381 def_ctx->Draw(3, 0);
1383 ComPtr<ID3D11CommandList> cmd_list;
1384 CHECK_HR_RET(def_ctx->FinishCommandList(FALSE, &cmd_list));
1385 dev_ctx->ExecuteCommandList(cmd_list.Get(), FALSE);
1400 ComPtr<IDirect3D11CaptureFrame> capture_frame;
1401 ComPtr<IDirect3DSurface> capture_surface;
1402 ComPtr<IDirect3DDxgiInterfaceAccess> dxgi_interface_access;
1403 ComPtr<ID3D11Texture2D> frame_texture;
1404 TimeSpan frame_time = { 0 };
1410 CHECK_HR_RET(capture_frame->get_SystemRelativeTime(&frame_time));
1412 CHECK_HR_RET(capture_frame->get_Surface(&capture_surface));
1413 CHECK_HR_RET(capture_surface.As(&dxgi_interface_access));
1414 CHECK_HR_RET(dxgi_interface_access->GetInterface(IID_PPV_ARGS(&frame_texture)));
1423 frame->pts = frame_time.Duration;
1448 if (!
ctx->first_pts)
1460 std::unique_ptr<GfxCaptureContextWgc> &wgctx =
ctx->wgc;
1462 std::lock_guard wgc_lock(
ctx->wgc_thread_uninit_mutex);
1471 std::unique_lock
frame_lock(wgctx->frame_arrived_mutex);
1474 uint64_t last_seq = wgctx->frame_seq.load(std::memory_order_acquire);
1480 if (wgctx->window_closed.load(std::memory_order_acquire)) {
1485 if (!wgctx->frame_arrived_cond.wait_for(
frame_lock, std::chrono::seconds(1), [&]() {
1486 return wgctx->frame_seq.load(std::memory_order_acquire) != last_seq ||
1487 wgctx->window_closed.load(std::memory_order_acquire);
1499 }
catch (
const std::exception &e) {
1510 }
catch (
const std::bad_alloc&) {
1512 }
catch (
const std::exception &e) {
1525 }
catch (
const std::bad_alloc&) {
1527 }
catch (
const std::exception &e) {
1542 }
catch (
const std::bad_alloc&) {
1544 }
catch (
const std::exception &e) {
1545 av_log(avctx,
AV_LOG_ERROR,
"unhandled exception during config_props: %s\n", e.what());