From 72d4982f54a69ec7e16aaa258671aa3217962a27 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Wed, 30 Aug 2023 17:44:22 +0800 Subject: [PATCH] Use kcp as QoS module --- demo/App.cpp | 85 ---- demo/App.h | 24 - demo/SimpleCapture.cpp | 217 --------- demo/SimpleCapture.h | 49 -- demo/Win32MonitorEnumeration.h | 50 --- demo/Win32WindowEnumeration.h | 101 ----- demo/capture.interop.h | 28 -- demo/composition.interop.h | 69 --- demo/d3dHelpers.h | 132 ------ demo/direct3d11.interop.h | 41 -- demo/main.cpp | 160 ------- demo/pch.cpp | 1 - demo/pch.h | 34 -- remote_desk.cpp.bak | 368 --------------- remote_desk_server/main.cpp | 12 + remote_desk_server/remote_desk_server.cpp | 93 ++++ remote_desk_server/remote_desk_server.h | 25 ++ dll/main.cpp => screen_capture/main.cpp.bak | 2 - .../screen_capture_wgc.cpp | 67 +-- {dll => screen_capture}/screen_capture_wgc.h | 19 +- {dll => screen_capture}/wgc_session.h | 0 {dll => screen_capture}/wgc_session_impl.cpp | 0 {dll => screen_capture}/wgc_session_impl.h | 0 webrtc/wgc_capture_session.cc | 372 ---------------- webrtc/wgc_capture_session.h | 110 ----- webrtc/wgc_capture_source.cc | 136 ------ webrtc/wgc_capture_source.h | 105 ----- webrtc/wgc_capture_source_unittest.cc | 113 ----- webrtc/wgc_capturer_win.cc | 218 --------- webrtc/wgc_capturer_win.h | 138 ------ webrtc/wgc_capturer_win_unittest.cc | 421 ------------------ webrtc/wgc_desktop_frame.cc | 19 - webrtc/wgc_desktop_frame.h | 35 -- xmake.lua | 32 +- 34 files changed, 157 insertions(+), 3119 deletions(-) delete mode 100644 demo/App.cpp delete mode 100644 demo/App.h delete mode 100644 demo/SimpleCapture.cpp delete mode 100644 demo/SimpleCapture.h delete mode 100644 demo/Win32MonitorEnumeration.h delete mode 100644 demo/Win32WindowEnumeration.h delete mode 100644 demo/capture.interop.h delete mode 100644 demo/composition.interop.h delete mode 100644 demo/d3dHelpers.h delete mode 100644 demo/direct3d11.interop.h delete mode 100644 demo/main.cpp delete mode 100644 demo/pch.cpp delete mode 100644 demo/pch.h delete mode 100644 remote_desk.cpp.bak create mode 100644 remote_desk_server/main.cpp create mode 100644 remote_desk_server/remote_desk_server.cpp create mode 100644 remote_desk_server/remote_desk_server.h rename dll/main.cpp => screen_capture/main.cpp.bak (97%) rename {dll => screen_capture}/screen_capture_wgc.cpp (54%) rename {dll => screen_capture}/screen_capture_wgc.h (79%) rename {dll => screen_capture}/wgc_session.h (100%) rename {dll => screen_capture}/wgc_session_impl.cpp (100%) rename {dll => screen_capture}/wgc_session_impl.h (100%) delete mode 100644 webrtc/wgc_capture_session.cc delete mode 100644 webrtc/wgc_capture_session.h delete mode 100644 webrtc/wgc_capture_source.cc delete mode 100644 webrtc/wgc_capture_source.h delete mode 100644 webrtc/wgc_capture_source_unittest.cc delete mode 100644 webrtc/wgc_capturer_win.cc delete mode 100644 webrtc/wgc_capturer_win.h delete mode 100644 webrtc/wgc_capturer_win_unittest.cc delete mode 100644 webrtc/wgc_desktop_frame.cc delete mode 100644 webrtc/wgc_desktop_frame.h diff --git a/demo/App.cpp b/demo/App.cpp deleted file mode 100644 index a4b8f3c..0000000 --- a/demo/App.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE SOFTWARE IS PROVIDED “AS IS? WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//********************************************************* - -#include "pch.h" -#include "App.h" -#include "SimpleCapture.h" - -using namespace winrt; -using namespace Windows::System; -using namespace Windows::Foundation; -using namespace Windows::UI; -using namespace Windows::UI::Composition; -using namespace Windows::Graphics::Capture; - -void App::Initialize(ContainerVisual const &root) { - auto queue = DispatcherQueue::GetForCurrentThread(); - - m_compositor = root.Compositor(); - m_root = m_compositor.CreateContainerVisual(); - m_content = m_compositor.CreateSpriteVisual(); - m_brush = m_compositor.CreateSurfaceBrush(); - - m_root.RelativeSizeAdjustment({1, 1}); - root.Children().InsertAtTop(m_root); - - m_content.AnchorPoint({0.5f, 0.5f}); - m_content.RelativeOffsetAdjustment({0.5f, 0.5f, 0}); - m_content.RelativeSizeAdjustment({1, 1}); - m_content.Size({-80, -80}); - m_content.Brush(m_brush); - m_brush.HorizontalAlignmentRatio(0.5f); - m_brush.VerticalAlignmentRatio(0.5f); - m_brush.Stretch(CompositionStretch::Uniform); - auto shadow = m_compositor.CreateDropShadow(); - shadow.Mask(m_brush); - m_content.Shadow(shadow); - m_root.Children().InsertAtTop(m_content); - - auto d3dDevice = CreateD3DDevice(); - auto dxgiDevice = d3dDevice.as(); - m_device = CreateDirect3DDevice(dxgiDevice.get()); -} - -void App::StartCapture(HWND hwnd) { - if (m_capture) { - m_capture->Close(); - m_capture = nullptr; - } - - auto item = CreateCaptureItemForWindow(hwnd); - - m_capture = std::make_unique(m_device, item); - - auto surface = m_capture->CreateSurface(m_compositor); - m_brush.Surface(surface); - - m_capture->StartCapture(); -} - -void App::StartCapture(HMONITOR hmonitor) { - if (m_capture) { - m_capture->Close(); - m_capture = nullptr; - } - - auto item = CreateCaptureItemForMonitor(hmonitor); - - m_capture = std::make_unique(m_device, item); - - auto surface = m_capture->CreateSurface(m_compositor); - m_brush.Surface(surface); - - m_capture->StartCapture(); -} \ No newline at end of file diff --git a/demo/App.h b/demo/App.h deleted file mode 100644 index 95cc2de..0000000 --- a/demo/App.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -class SimpleCapture; - -class App { -public: - App() {} - ~App() {} - - void Initialize(winrt::Windows::UI::Composition::ContainerVisual const &root); - - void StartCapture(HWND hwnd); - void StartCapture(HMONITOR hmonitor); - -private: - winrt::Windows::UI::Composition::Compositor m_compositor{nullptr}; - winrt::Windows::UI::Composition::ContainerVisual m_root{nullptr}; - winrt::Windows::UI::Composition::SpriteVisual m_content{nullptr}; - winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr}; - - winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_device{ - nullptr}; - std::unique_ptr m_capture{nullptr}; -}; \ No newline at end of file diff --git a/demo/SimpleCapture.cpp b/demo/SimpleCapture.cpp deleted file mode 100644 index ec72bb2..0000000 --- a/demo/SimpleCapture.cpp +++ /dev/null @@ -1,217 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE SOFTWARE IS PROVIDED “AS IS? WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//********************************************************* - -#include "SimpleCapture.h" - -#include "pch.h" - -using namespace winrt; -using namespace Windows; -using namespace Windows::Foundation; -using namespace Windows::System; -using namespace Windows::Graphics; -using namespace Windows::Graphics::Capture; -using namespace Windows::Graphics::DirectX; -using namespace Windows::Graphics::DirectX::Direct3D11; -using namespace Windows::Foundation::Numerics; -using namespace Windows::UI; -using namespace Windows::UI::Composition; - -SimpleCapture::SimpleCapture(IDirect3DDevice const &device, - GraphicsCaptureItem const &item) { - m_item = item; - m_device = device; - - // Set up - auto d3dDevice = GetDXGIInterfaceFromObject(m_device); - d3dDevice->GetImmediateContext(m_d3dContext.put()); - - auto size = m_item.Size(); - - m_swapChain = CreateDXGISwapChain( - d3dDevice, static_cast(size.Width), - static_cast(size.Height), - static_cast(DirectXPixelFormat::B8G8R8A8UIntNormalized), 2); - - // Create framepool, define pixel format (DXGI_FORMAT_B8G8R8A8_UNORM), and - // frame size. - m_framePool = Direct3D11CaptureFramePool::Create( - m_device, DirectXPixelFormat::B8G8R8A8UIntNormalized, 2, size); - m_session = m_framePool.CreateCaptureSession(m_item); - m_lastSize = size; - m_frameArrived = m_framePool.FrameArrived( - auto_revoke, {this, &SimpleCapture::OnFrameArrived}); -} - -// Start sending capture frames -void SimpleCapture::StartCapture() { - CheckClosed(); - m_session.StartCapture(); -} - -ICompositionSurface SimpleCapture::CreateSurface(Compositor const &compositor) { - CheckClosed(); - return CreateCompositionSurfaceForSwapChain(compositor, m_swapChain.get()); -} - -// Process captured frames -void SimpleCapture::Close() { - auto expected = false; - if (m_closed.compare_exchange_strong(expected, true)) { - m_frameArrived.revoke(); - m_framePool.Close(); - m_session.Close(); - - m_swapChain = nullptr; - m_framePool = nullptr; - m_session = nullptr; - m_item = nullptr; - } -} - -void SimpleCapture::OnFrameArrived( - Direct3D11CaptureFramePool const &sender, - winrt::Windows::Foundation::IInspectable const &) { - auto newSize = false; - - { - auto frame = sender.TryGetNextFrame(); - auto frameContentSize = frame.ContentSize(); - - if (frameContentSize.Width != m_lastSize.Width || - frameContentSize.Height != m_lastSize.Height) { - // The thing we have been capturing has changed size. - // We need to resize our swap chain first, then blit the pixels. - // After we do that, retire the frame and then recreate our frame pool. - newSize = true; - m_lastSize = frameContentSize; - m_swapChain->ResizeBuffers( - 2, static_cast(m_lastSize.Width), - static_cast(m_lastSize.Height), - static_cast(DirectXPixelFormat::B8G8R8A8UIntNormalized), - 0); - } - - // copy to swapChain - { - auto frameSurface = - GetDXGIInterfaceFromObject(frame.Surface()); - - com_ptr backBuffer; - check_hresult(m_swapChain->GetBuffer(0, guid_of(), - backBuffer.put_void())); - - m_d3dContext->CopyResource(backBuffer.get(), frameSurface.get()); - - DXGI_PRESENT_PARAMETERS presentParameters = {0}; - m_swapChain->Present1(1, 0, &presentParameters); - } - - // copy to mapped texture - { - auto frameSurface = - GetDXGIInterfaceFromObject(frame.Surface()); - - if (!m_mappedTexture || newSize) CreateMappedTexture(frameSurface); - - m_d3dContext->CopyResource(m_mappedTexture.get(), frameSurface.get()); - - D3D11_MAPPED_SUBRESOURCE mapInfo; - m_d3dContext->Map(m_mappedTexture.get(), 0, D3D11_MAP_READ, - D3D11_MAP_FLAG_DO_NOT_WAIT, &mapInfo); - - // copy data from mapInfo.pData -#if 1 - if (mapInfo.pData) { - static unsigned char *buffer = nullptr; - if (buffer && newSize) delete[] buffer; - - if (!buffer) - buffer = new unsigned char[frameContentSize.Width * - frameContentSize.Height * 4]; - - int dstRowPitch = frameContentSize.Width * 4; - for (int h = 0; h < frameContentSize.Height; h++) { - memcpy_s(buffer + h * dstRowPitch, dstRowPitch, - (BYTE *)mapInfo.pData + h * mapInfo.RowPitch, - min(mapInfo.RowPitch, dstRowPitch)); - } - - BITMAPINFOHEADER bi; - - bi.biSize = sizeof(BITMAPINFOHEADER); - bi.biWidth = frameContentSize.Width; - bi.biHeight = frameContentSize.Height * (-1); - bi.biPlanes = 1; - bi.biBitCount = 32; // should get from system color bits - bi.biCompression = BI_RGB; - bi.biSizeImage = 0; - bi.biXPelsPerMeter = 0; - bi.biYPelsPerMeter = 0; - bi.biClrUsed = 0; - bi.biClrImportant = 0; - - BITMAPFILEHEADER bf; - bf.bfType = 0x4d42; - bf.bfReserved1 = 0; - bf.bfReserved2 = 0; - bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); - bf.bfSize = - bf.bfOffBits + frameContentSize.Width * frameContentSize.Height * 4; - - FILE *fp = nullptr; - - fopen_s(&fp, ".\\save.bmp", "wb+"); - - fwrite(&bf, 1, sizeof(bf), fp); - fwrite(&bi, 1, sizeof(bi), fp); - fwrite(buffer, 1, frameContentSize.Width * frameContentSize.Height * 4, - fp); - - fflush(fp); - fclose(fp); - } -#endif - - m_d3dContext->Unmap(m_mappedTexture.get(), 0); - } - } - - if (newSize) { - m_framePool.Recreate(m_device, DirectXPixelFormat::B8G8R8A8UIntNormalized, - 2, m_lastSize); - } -} - -HRESULT -SimpleCapture::CreateMappedTexture(winrt::com_ptr src_texture, - UINT width, UINT height) { - D3D11_TEXTURE2D_DESC src_desc; - src_texture->GetDesc(&src_desc); - D3D11_TEXTURE2D_DESC map_desc; - map_desc.Width = width == 0 ? src_desc.Width : width; - map_desc.Height = height == 0 ? src_desc.Height : height; - map_desc.MipLevels = src_desc.MipLevels; - map_desc.ArraySize = src_desc.ArraySize; - map_desc.Format = src_desc.Format; - map_desc.SampleDesc = src_desc.SampleDesc; - map_desc.Usage = D3D11_USAGE_STAGING; - map_desc.BindFlags = 0; - map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - map_desc.MiscFlags = 0; - - auto d3dDevice = GetDXGIInterfaceFromObject(m_device); - - return d3dDevice->CreateTexture2D(&map_desc, nullptr, m_mappedTexture.put()); -} diff --git a/demo/SimpleCapture.h b/demo/SimpleCapture.h deleted file mode 100644 index ce66db3..0000000 --- a/demo/SimpleCapture.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -class SimpleCapture { -public: - SimpleCapture( - winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice const - &device, - winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &item); - ~SimpleCapture() { Close(); } - - void StartCapture(); - winrt::Windows::UI::Composition::ICompositionSurface - CreateSurface(winrt::Windows::UI::Composition::Compositor const &compositor); - - void Close(); - -private: - void OnFrameArrived( - winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const - &sender, - winrt::Windows::Foundation::IInspectable const &args); - - void CheckClosed() { - if (m_closed.load() == true) { - throw winrt::hresult_error(RO_E_CLOSED); - } - } - - HRESULT - CreateMappedTexture(winrt::com_ptr src_texture, - UINT width = 0, UINT height = 0); - -private: - winrt::Windows::Graphics::Capture::GraphicsCaptureItem m_item{nullptr}; - winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool m_framePool{ - nullptr}; - winrt::Windows::Graphics::Capture::GraphicsCaptureSession m_session{nullptr}; - winrt::Windows::Graphics::SizeInt32 m_lastSize; - - winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_device{ - nullptr}; - winrt::com_ptr m_swapChain{nullptr}; - winrt::com_ptr m_d3dContext{nullptr}; - winrt::com_ptr m_mappedTexture{nullptr}; - - std::atomic m_closed = false; - winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool:: - FrameArrived_revoker m_frameArrived; -}; \ No newline at end of file diff --git a/demo/Win32MonitorEnumeration.h b/demo/Win32MonitorEnumeration.h deleted file mode 100644 index e9e7bca..0000000 --- a/demo/Win32MonitorEnumeration.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include - -struct Monitor { -public: - Monitor(nullptr_t) {} - Monitor(HMONITOR hmonitor, std::wstring &className, bool isPrimary) { - m_hmonitor = hmonitor; - m_className = className; - m_bIsPrimary = isPrimary; - } - - HMONITOR Hmonitor() const noexcept { return m_hmonitor; } - std::wstring ClassName() const noexcept { return m_className; } - bool IsPrimary() const noexcept { return m_bIsPrimary; } - -private: - HMONITOR m_hmonitor; - std::wstring m_className; - bool m_bIsPrimary; -}; - -BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, HDC hdc, LPRECT lprc, - LPARAM data) { - - MONITORINFOEX info_ex; - info_ex.cbSize = sizeof(MONITORINFOEX); - - GetMonitorInfo(hmonitor, &info_ex); - - if (info_ex.dwFlags == DISPLAY_DEVICE_MIRRORING_DRIVER) - return true; - - auto monitors = ((std::vector *)data); - std::wstring name = info_ex.szDevice; - auto monitor = - Monitor(hmonitor, name, info_ex.dwFlags & MONITORINFOF_PRIMARY); - - monitors->emplace_back(monitor); - - return true; -} - -std::vector EnumerateMonitors() { - std::vector monitors; - - ::EnumDisplayMonitors(NULL, NULL, EnumMonitorProc, (LPARAM)&monitors); - - return monitors; -} \ No newline at end of file diff --git a/demo/Win32WindowEnumeration.h b/demo/Win32WindowEnumeration.h deleted file mode 100644 index 20761c2..0000000 --- a/demo/Win32WindowEnumeration.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once -#include - -struct Window { -public: - Window(nullptr_t) {} - Window(HWND hwnd, std::wstring const &title, std::wstring &className) { - m_hwnd = hwnd; - m_title = title; - m_className = className; - } - - HWND Hwnd() const noexcept { return m_hwnd; } - std::wstring Title() const noexcept { return m_title; } - std::wstring ClassName() const noexcept { return m_className; } - -private: - HWND m_hwnd; - std::wstring m_title; - std::wstring m_className; -}; - -std::wstring GetClassName(HWND hwnd) { - std::array className; - - ::GetClassName(hwnd, className.data(), (int)className.size()); - - std::wstring title(className.data()); - return title; -} - -std::wstring GetWindowText(HWND hwnd) { - std::array windowText; - - ::GetWindowText(hwnd, windowText.data(), (int)windowText.size()); - - std::wstring title(windowText.data()); - return title; -} - -bool IsAltTabWindow(Window const &window) { - HWND hwnd = window.Hwnd(); - HWND shellWindow = GetShellWindow(); - - auto title = window.Title(); - auto className = window.ClassName(); - - if (hwnd == shellWindow) { - return false; - } - - if (title.length() == 0) { - return false; - } - - if (!IsWindowVisible(hwnd)) { - return false; - } - - if (GetAncestor(hwnd, GA_ROOT) != hwnd) { - return false; - } - - LONG style = GetWindowLong(hwnd, GWL_STYLE); - if (!((style & WS_DISABLED) != WS_DISABLED)) { - return false; - } - - DWORD cloaked = FALSE; - HRESULT hrTemp = - DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, sizeof(cloaked)); - if (SUCCEEDED(hrTemp) && cloaked == DWM_CLOAKED_SHELL) { - return false; - } - - return true; -} - -BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { - auto class_name = GetClassName(hwnd); - auto title = GetWindowText(hwnd); - - auto window = Window(hwnd, title, class_name); - - if (!IsAltTabWindow(window)) { - return TRUE; - } - - std::vector &windows = - *reinterpret_cast *>(lParam); - windows.push_back(window); - - return TRUE; -} - -const std::vector EnumerateWindows() { - std::vector windows; - EnumWindows(EnumWindowsProc, reinterpret_cast(&windows)); - - return windows; -} \ No newline at end of file diff --git a/demo/capture.interop.h b/demo/capture.interop.h deleted file mode 100644 index 2232672..0000000 --- a/demo/capture.interop.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include -#include -#include - -inline auto CreateCaptureItemForWindow(HWND hwnd) { - auto activation_factory = winrt::get_activation_factory< - winrt::Windows::Graphics::Capture::GraphicsCaptureItem>(); - auto interop_factory = activation_factory.as(); - winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr}; - interop_factory->CreateForWindow( - hwnd, - winrt::guid_of(), - reinterpret_cast(winrt::put_abi(item))); - return item; -} - -inline auto CreateCaptureItemForMonitor(HMONITOR hmonitor) { - auto activation_factory = winrt::get_activation_factory< - winrt::Windows::Graphics::Capture::GraphicsCaptureItem>(); - auto interop_factory = activation_factory.as(); - winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr}; - interop_factory->CreateForMonitor( - hmonitor, - winrt::guid_of(), - reinterpret_cast(winrt::put_abi(item))); - return item; -} \ No newline at end of file diff --git a/demo/composition.interop.h b/demo/composition.interop.h deleted file mode 100644 index 01a10ce..0000000 --- a/demo/composition.interop.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include -#include -#include - -inline auto CreateCompositionGraphicsDevice( - winrt::Windows::UI::Composition::Compositor const &compositor, - ::IUnknown *device) { - winrt::Windows::UI::Composition::CompositionGraphicsDevice graphicsDevice{ - nullptr}; - auto compositorInterop = - compositor.as(); - winrt::com_ptr - graphicsInterop; - winrt::check_hresult( - compositorInterop->CreateGraphicsDevice(device, graphicsInterop.put())); - winrt::check_hresult(graphicsInterop->QueryInterface( - winrt::guid_of< - winrt::Windows::UI::Composition::CompositionGraphicsDevice>(), - reinterpret_cast(winrt::put_abi(graphicsDevice)))); - return graphicsDevice; -} - -inline void ResizeSurface( - winrt::Windows::UI::Composition::CompositionDrawingSurface const &surface, - winrt::Windows::Foundation::Size const &size) { - auto surfaceInterop = surface.as< - ABI::Windows::UI::Composition::ICompositionDrawingSurfaceInterop>(); - SIZE newSize = {}; - newSize.cx = static_cast(std::round(size.Width)); - newSize.cy = static_cast(std::round(size.Height)); - winrt::check_hresult(surfaceInterop->Resize(newSize)); -} - -inline auto SurfaceBeginDraw( - winrt::Windows::UI::Composition::CompositionDrawingSurface const &surface) { - auto surfaceInterop = surface.as< - ABI::Windows::UI::Composition::ICompositionDrawingSurfaceInterop>(); - winrt::com_ptr context; - POINT offset = {}; - winrt::check_hresult(surfaceInterop->BeginDraw( - nullptr, __uuidof(ID2D1DeviceContext), context.put_void(), &offset)); - context->SetTransform( - D2D1::Matrix3x2F::Translation((FLOAT)offset.x, (FLOAT)offset.y)); - return context; -} - -inline void SurfaceEndDraw( - winrt::Windows::UI::Composition::CompositionDrawingSurface const &surface) { - auto surfaceInterop = surface.as< - ABI::Windows::UI::Composition::ICompositionDrawingSurfaceInterop>(); - winrt::check_hresult(surfaceInterop->EndDraw()); -} - -inline auto CreateCompositionSurfaceForSwapChain( - winrt::Windows::UI::Composition::Compositor const &compositor, - ::IUnknown *swapChain) { - winrt::Windows::UI::Composition::ICompositionSurface surface{nullptr}; - auto compositorInterop = - compositor.as(); - winrt::com_ptr - surfaceInterop; - winrt::check_hresult(compositorInterop->CreateCompositionSurfaceForSwapChain( - swapChain, surfaceInterop.put())); - winrt::check_hresult(surfaceInterop->QueryInterface( - winrt::guid_of(), - reinterpret_cast(winrt::put_abi(surface)))); - return surface; -} \ No newline at end of file diff --git a/demo/d3dHelpers.h b/demo/d3dHelpers.h deleted file mode 100644 index c5d87f5..0000000 --- a/demo/d3dHelpers.h +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once -#include "composition.interop.h" - -struct SurfaceContext { -public: - SurfaceContext(std::nullptr_t) {} - SurfaceContext( - winrt::Windows::UI::Composition::CompositionDrawingSurface surface) { - m_surface = surface; - m_d2dContext = SurfaceBeginDraw(m_surface); - } - ~SurfaceContext() { - SurfaceEndDraw(m_surface); - m_d2dContext = nullptr; - m_surface = nullptr; - } - - winrt::com_ptr GetDeviceContext() { return m_d2dContext; } - -private: - winrt::com_ptr m_d2dContext; - winrt::Windows::UI::Composition::CompositionDrawingSurface m_surface{nullptr}; -}; - -struct D3D11DeviceLock { -public: - D3D11DeviceLock(std::nullopt_t) {} - D3D11DeviceLock(ID3D11Multithread *pMultithread) { - m_multithread.copy_from(pMultithread); - m_multithread->Enter(); - } - ~D3D11DeviceLock() { - m_multithread->Leave(); - m_multithread = nullptr; - } - -private: - winrt::com_ptr m_multithread; -}; - -inline auto CreateWICFactory() { - winrt::com_ptr wicFactory; - winrt::check_hresult(::CoCreateInstance( - CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, - winrt::guid_of(), wicFactory.put_void())); - - return wicFactory; -} - -inline auto CreateD2DDevice(winrt::com_ptr const &factory, - winrt::com_ptr const &device) { - winrt::com_ptr result; - winrt::check_hresult( - factory->CreateDevice(device.as().get(), result.put())); - return result; -} - -inline auto CreateD3DDevice(D3D_DRIVER_TYPE const type, - winrt::com_ptr &device) { - WINRT_ASSERT(!device); - - UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; - - //#ifdef _DEBUG - // flags |= D3D11_CREATE_DEVICE_DEBUG; - //#endif - - return D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0, - D3D11_SDK_VERSION, device.put(), nullptr, nullptr); -} - -inline auto CreateD3DDevice() { - winrt::com_ptr device; - HRESULT hr = CreateD3DDevice(D3D_DRIVER_TYPE_HARDWARE, device); - - if (DXGI_ERROR_UNSUPPORTED == hr) { - hr = CreateD3DDevice(D3D_DRIVER_TYPE_WARP, device); - } - - winrt::check_hresult(hr); - return device; -} - -inline auto CreateD2DFactory() { - D2D1_FACTORY_OPTIONS options{}; - - //#ifdef _DEBUG - // options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; - //#endif - - winrt::com_ptr factory; - - winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, - options, factory.put())); - - return factory; -} - -inline auto CreateDXGISwapChain(winrt::com_ptr const &device, - const DXGI_SWAP_CHAIN_DESC1 *desc) { - auto dxgiDevice = device.as(); - winrt::com_ptr adapter; - winrt::check_hresult(dxgiDevice->GetParent(winrt::guid_of(), - adapter.put_void())); - winrt::com_ptr factory; - winrt::check_hresult( - adapter->GetParent(winrt::guid_of(), factory.put_void())); - - winrt::com_ptr swapchain; - winrt::check_hresult(factory->CreateSwapChainForComposition( - device.get(), desc, nullptr, swapchain.put())); - - return swapchain; -} - -inline auto CreateDXGISwapChain(winrt::com_ptr const &device, - uint32_t width, uint32_t height, - DXGI_FORMAT format, uint32_t bufferCount) { - DXGI_SWAP_CHAIN_DESC1 desc = {}; - desc.Width = width; - desc.Height = height; - desc.Format = format; - desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.BufferCount = bufferCount; - desc.Scaling = DXGI_SCALING_STRETCH; - desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED; - - return CreateDXGISwapChain(device, &desc); -} \ No newline at end of file diff --git a/demo/direct3d11.interop.h b/demo/direct3d11.interop.h deleted file mode 100644 index d282bbe..0000000 --- a/demo/direct3d11.interop.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#include - -extern "C" { -HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice( - ::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice); - -HRESULT __stdcall CreateDirect3D11SurfaceFromDXGISurface( - ::IDXGISurface *dgxiSurface, ::IInspectable **graphicsSurface); -} - -struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1")) - IDirect3DDxgiInterfaceAccess : ::IUnknown { - virtual HRESULT __stdcall GetInterface(GUID const &id, void **object) = 0; -}; - -inline auto CreateDirect3DDevice(IDXGIDevice *dxgi_device) { - winrt::com_ptr<::IInspectable> d3d_device; - winrt::check_hresult( - CreateDirect3D11DeviceFromDXGIDevice(dxgi_device, d3d_device.put())); - return d3d_device - .as(); -} - -inline auto CreateDirect3DSurface(IDXGISurface *dxgi_surface) { - winrt::com_ptr<::IInspectable> d3d_surface; - winrt::check_hresult( - CreateDirect3D11SurfaceFromDXGISurface(dxgi_surface, d3d_surface.put())); - return d3d_surface - .as(); -} - -template -auto GetDXGIInterfaceFromObject( - winrt::Windows::Foundation::IInspectable const &object) { - auto access = object.as(); - winrt::com_ptr result; - winrt::check_hresult( - access->GetInterface(winrt::guid_of(), result.put_void())); - return result; -} \ No newline at end of file diff --git a/demo/main.cpp b/demo/main.cpp deleted file mode 100644 index 9f0e68d..0000000 --- a/demo/main.cpp +++ /dev/null @@ -1,160 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE SOFTWARE IS PROVIDED “AS IS? WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -//********************************************************* - -#include "pch.h" -#include "App.h" -#include "SimpleCapture.h" -#include "Win32MonitorEnumeration.h" -#include "Win32WindowEnumeration.h" -#include - -using namespace winrt; -using namespace Windows::UI; -using namespace Windows::UI::Composition; -using namespace Windows::UI::Composition::Desktop; - -// Direct3D11CaptureFramePool requires a DispatcherQueue -auto CreateDispatcherQueueController() { - namespace abi = ABI::Windows::System; - - DispatcherQueueOptions options{sizeof(DispatcherQueueOptions), - DQTYPE_THREAD_CURRENT, DQTAT_COM_STA}; - - Windows::System::DispatcherQueueController controller{nullptr}; - check_hresult(CreateDispatcherQueueController( - options, reinterpret_cast( - put_abi(controller)))); - return controller; -} - -DesktopWindowTarget CreateDesktopWindowTarget(Compositor const &compositor, - HWND window) { - namespace abi = ABI::Windows::UI::Composition::Desktop; - - auto interop = compositor.as(); - DesktopWindowTarget target{nullptr}; - check_hresult(interop->CreateDesktopWindowTarget( - window, true, - reinterpret_cast(put_abi(target)))); - return target; -} - -int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, - LPSTR cmdLine, int cmdShow); - -auto g_app = std::make_shared(); -auto g_windows = EnumerateWindows(); -auto g_monitors = EnumerateMonitors(); - -LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - -int CALLBACK WinMain(HINSTANCE instance, HINSTANCE previousInstance, - LPSTR cmdLine, int cmdShow) { - // Init COM - init_apartment(apartment_type::single_threaded); - - // Create the window - WNDCLASSEX wcex = {}; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = instance; - wcex.hIcon = LoadIcon(instance, MAKEINTRESOURCE(IDI_APPLICATION)); - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = NULL; - wcex.lpszClassName = L"ScreenCaptureforHWND"; - wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); - WINRT_VERIFY(RegisterClassEx(&wcex)); - - HWND hwnd = CreateWindow(L"ScreenCaptureforHWND", L"ScreenCaptureforHWND", - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - 800, 600, NULL, NULL, instance, NULL); - WINRT_VERIFY(hwnd); - - ShowWindow(hwnd, cmdShow); - UpdateWindow(hwnd); - - // Create combo box - HWND comboBoxHwnd = - CreateWindow(WC_COMBOBOX, L"", - CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_VSCROLL | WS_CHILD | - WS_OVERLAPPED | WS_VISIBLE, - 10, 10, 200, 200, hwnd, NULL, instance, NULL); - WINRT_VERIFY(comboBoxHwnd); - - // Populate combo box - // for (auto &window : g_windows) { - // SendMessage(comboBoxHwnd, CB_ADDSTRING, 0, (LPARAM)window.Title().c_str()); - // } - - for (auto &monitor : g_monitors) { - SendMessage(comboBoxHwnd, CB_ADDSTRING, 0, - (LPARAM)monitor.ClassName().c_str()); - } - - // SendMessage(comboBoxHwnd, CB_SETCURSEL, 0, 0); - - // Create a DispatcherQueue for our thread - auto controller = CreateDispatcherQueueController(); - - // Initialize Composition - auto compositor = Compositor(); - auto target = CreateDesktopWindowTarget(compositor, hwnd); - auto root = compositor.CreateContainerVisual(); - root.RelativeSizeAdjustment({1.0f, 1.0f}); - target.Root(root); - - // Enqueue our capture work on the dispatcher - auto queue = controller.DispatcherQueue(); - auto success = queue.TryEnqueue([=]() -> void { g_app->Initialize(root); }); - WINRT_VERIFY(success); - - // Message pump - MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return (int)msg.wParam; -} - -LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - switch (msg) { - case WM_DESTROY: - PostQuitMessage(0); - break; - case WM_COMMAND: - if (HIWORD(wParam) == CBN_SELCHANGE) { - auto index = SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0); - // if (index < g_windows.size() - 1) { - // auto window = g_windows[index]; - // g_app->StartCapture(window.Hwnd()); - // } else { - // auto monitor = g_monitors[index - g_windows.size()]; - auto monitor = g_monitors[0]; - g_app->StartCapture(monitor.Hmonitor()); - // } - } - break; - default: - return DefWindowProc(hwnd, msg, wParam, lParam); - break; - } - - return 0; -} \ No newline at end of file diff --git a/demo/pch.cpp b/demo/pch.cpp deleted file mode 100644 index 1730571..0000000 --- a/demo/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" \ No newline at end of file diff --git a/demo/pch.h b/demo/pch.h deleted file mode 100644 index 54bdc4a..0000000 --- a/demo/pch.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include - -// WinRT -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -// STL -#include -#include - -// D3D -#include -#include -#include -#include - -// Helpers -#include "composition.interop.h" -#include "d3dHelpers.h" -#include "direct3d11.interop.h" -#include "capture.interop.h" \ No newline at end of file diff --git a/remote_desk.cpp.bak b/remote_desk.cpp.bak deleted file mode 100644 index 1e0b40b..0000000 --- a/remote_desk.cpp.bak +++ /dev/null @@ -1,368 +0,0 @@ -#include - -#define __STDC_CONSTANT_MACROS - -#ifdef _WIN32 -// Windows -extern "C" { -#include -#include -#include -#include -#include - -#include "SDL2/SDL.h" -}; -#else -// Linux... -#ifdef __cplusplus -extern "C" { -#endif -#include -#include -#include -#include -#include -#ifdef __cplusplus -}; -#endif -#endif - -// Output YUV420P -#define OUTPUT_YUV420P 0 -//'1' Use Dshow -//'0' Use GDIgrab -#define USE_DSHOW 0 - -// Refresh Event -#define SFM_REFRESH_EVENT (SDL_USEREVENT + 1) - -#define SFM_BREAK_EVENT (SDL_USEREVENT + 2) - -int thread_exit = 0; -SDL_Texture *sdlTexture = nullptr; -SDL_Renderer *sdlRenderer = nullptr; -SDL_Rect sdlRect; - -int YUV420ToNV12FFmpeg(unsigned char *src_buffer, int width, int height, - unsigned char *des_buffer) { - AVFrame *Input_pFrame = av_frame_alloc(); - AVFrame *Output_pFrame = av_frame_alloc(); - struct SwsContext *img_convert_ctx = sws_getContext( - width, height, AV_PIX_FMT_NV12, width, height, AV_PIX_FMT_YUV420P, - SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); - - av_image_fill_arrays(Input_pFrame->data, Input_pFrame->linesize, src_buffer, - AV_PIX_FMT_NV12, width, height, 1); - av_image_fill_arrays(Output_pFrame->data, Output_pFrame->linesize, des_buffer, - AV_PIX_FMT_YUV420P, width, height, 1); - - sws_scale(img_convert_ctx, (uint8_t const **)Input_pFrame->data, - Input_pFrame->linesize, 0, height, Output_pFrame->data, - Output_pFrame->linesize); - - if (Input_pFrame) av_free(Input_pFrame); - if (Output_pFrame) av_free(Output_pFrame); - if (img_convert_ctx) sws_freeContext(img_convert_ctx); - - return 0; -} - -int sfp_refresh_thread(void *opaque) { - thread_exit = 0; - while (!thread_exit) { - SDL_Event event; - event.type = SFM_REFRESH_EVENT; - SDL_PushEvent(&event); - SDL_Delay(40); - } - thread_exit = 0; - // Break - SDL_Event event; - event.type = SFM_BREAK_EVENT; - SDL_PushEvent(&event); - - return 0; -} - -// Show Dshow Device -// void show_dshow_device() { -// AVFormatContext *pFormatCtx = avformat_alloc_context(); -// AVDictionary *options = NULL; -// av_dict_set(&options, "list_devices", "true", 0); -// AVInputFormat *iformat = av_find_input_format("dshow"); -// printf("========Device Info=============\n"); -// avformat_open_input(&pFormatCtx, "video=dummy", iformat, &options); -// printf("================================\n"); -// } - -// Show AVFoundation Device -void show_avfoundation_device() { - const AVFormatContext *const_pFormatCtx = avformat_alloc_context(); - AVFormatContext *pFormatCtx = const_cast(const_pFormatCtx); - - AVDictionary *options = NULL; - av_dict_set(&options, "list_devices", "true", 0); - const AVInputFormat *const_iformat = av_find_input_format("avfoundation"); - AVInputFormat *iformat = const_cast(const_iformat); - - printf("==AVFoundation Device Info===\n"); - avformat_open_input(&pFormatCtx, "", iformat, &options); - printf("=============================\n"); -} - -int main(int argc, char *argv[]) { - AVFormatContext *pFormatCtx; - int i, videoindex; - AVCodecContext *pCodecCtx; - AVCodec *pCodec; - - avformat_network_init(); - pFormatCtx = avformat_alloc_context(); - - // Open File - // char filepath[]="src01_480x272_22.h265"; - // avformat_open_input(&pFormatCtx,filepath,NULL,NULL) - - // Register Device - avdevice_register_all(); - // Windows -#ifdef _WIN32 -#if USE_DSHOW - // Use dshow - // - // Need to Install screen-capture-recorder - // screen-capture-recorder - // Website: http://sourceforge.net/projects/screencapturer/ - // - AVInputFormat *ifmt = av_find_input_format("dshow"); - if (avformat_open_input(&pFormatCtx, "video=screen-capture-recorder", ifmt, - NULL) != 0) { - printf("Couldn't open input stream.\n"); - return -1; - } -#else - // Use gdigrab - AVDictionary *options = NULL; - // Set some options - // grabbing frame rate - // av_dict_set(&options,"framerate","5",0); - // The distance from the left edge of the screen or desktop - // av_dict_set(&options,"offset_x","20",0); - // The distance from the top edge of the screen or desktop - // av_dict_set(&options,"offset_y","40",0); - // Video frame size. The default is to capture the full screen - // av_dict_set(&options,"video_size","640x480",0); - const AVInputFormat *ifmt = av_find_input_format("gdigrab"); - if (avformat_open_input(&pFormatCtx, "desktop", ifmt, &options) != 0) { - printf("Couldn't open input stream.\n"); - return -1; - } - -#endif -#elif defined linux - // Linux - AVDictionary *options = NULL; - // Set some options - // grabbing frame rate - // av_dict_set(&options,"framerate","5",0); - // Make the grabbed area follow the mouse - // av_dict_set(&options,"follow_mouse","centered",0); - // Video frame size. The default is to capture the full screen - // av_dict_set(&options,"video_size","640x480",0); - AVInputFormat *ifmt = av_find_input_format("x11grab"); - // Grab at position 10,20 - if (avformat_open_input(&pFormatCtx, ":0.0+10,20", ifmt, &options) != 0) { - printf("Couldn't open input stream.\n"); - return -1; - } -#else - show_avfoundation_device(); - // Mac - AVInputFormat *ifmt = av_find_input_format("avfoundation"); - // Avfoundation - //[video]:[audio] - if (avformat_open_input(&pFormatCtx, "1", ifmt, NULL) != 0) { - printf("Couldn't open input stream.\n"); - return -1; - } -#endif - - if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { - printf("Couldn't find stream information.\n"); - return -1; - } - videoindex = -1; - for (i = 0; i < pFormatCtx->nb_streams; i++) - if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - videoindex = i; - break; - } - if (videoindex == -1) { - printf("Didn't find a video stream.\n"); - return -1; - } - // pCodecCtx = pFormatCtx->streams[videoindex]->codec; - - pCodecCtx = avcodec_alloc_context3(NULL); - avcodec_parameters_to_context(pCodecCtx, - pFormatCtx->streams[videoindex]->codecpar); - - pCodec = const_cast(avcodec_find_decoder(pCodecCtx->codec_id)); - // pCodec = avcodec_find_decoder(pCodecCtx->codec_id); - if (pCodec == NULL) { - printf("Codec not found.\n"); - return -1; - } - if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { - printf("Could not open codec.\n"); - return -1; - } - AVFrame *pFrame, *pFrameYUV; - pFrame = av_frame_alloc(); - pFrameYUV = av_frame_alloc(); - // unsigned char *out_buffer=(unsigned char - // *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, - // pCodecCtx->height)); avpicture_fill((AVPicture *)pFrameYUV, out_buffer, - // AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height); - // SDL---------------------------- - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { - printf("Could not initialize SDL - %s\n", SDL_GetError()); - return -1; - } - const int pixel_w = 640, pixel_h = 360; - int screen_w = 640, screen_h = 360; - // const SDL_VideoInfo *vi = SDL_GetVideoInfo(); - // Half of the Desktop's width and height. - screen_w = 640; - screen_h = 360; - // SDL_Surface *screen; - // screen = SDL_SetVideoMode(screen_w, screen_h, 0, 0); - SDL_Window *screen; - screen = SDL_CreateWindow("RTS Receiver", SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, - SDL_WINDOW_RESIZABLE); - - if (!screen) { - printf("SDL: could not set video mode - exiting:%s\n", SDL_GetError()); - return -1; - } - // SDL_Overlay *bmp; - // bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, - // SDL_YV12_OVERLAY, screen); - - sdlRenderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED); - - Uint32 pixformat = 0; - pixformat = SDL_PIXELFORMAT_NV12; - - SDL_Texture *sdlTexture = nullptr; - sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, - SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h); - - SDL_Rect rect; - rect.x = 0; - rect.y = 0; - rect.w = screen_w; - rect.h = screen_h; - // SDL End------------------------ - int ret, got_picture; - - AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket)); - -#if OUTPUT_YUV420P - FILE *fp_yuv = fopen("output.yuv", "wb+"); -#endif - - struct SwsContext *img_convert_ctx; - img_convert_ctx = sws_getContext( - pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, - pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); - //------------------------------ - SDL_Thread *video_tid = SDL_CreateThread(sfp_refresh_thread, NULL, NULL); - // - // SDL_WM_SetCaption("Simplest FFmpeg Grab Desktop", NULL); - // Event Loop - SDL_Event event; - - for (;;) { - // Wait - SDL_WaitEvent(&event); - if (event.type == SFM_REFRESH_EVENT) { - //------------------------------ - if (av_read_frame(pFormatCtx, packet) >= 0) { - if (packet->stream_index == videoindex) { - avcodec_send_packet(pCodecCtx, packet); - got_picture = avcodec_receive_frame(pCodecCtx, pFrame); - // ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, - // packet); - if (ret < 0) { - printf("Decode Error.\n"); - return -1; - } - if (got_picture) { - // SDL_LockYUVOverlay(bmp); - // pFrameYUV->data[0] = bmp->pixels[0]; - // pFrameYUV->data[1] = bmp->pixels[2]; - // pFrameYUV->data[2] = bmp->pixels[1]; - // pFrameYUV->linesize[0] = bmp->pitches[0]; - // pFrameYUV->linesize[1] = bmp->pitches[2]; - // pFrameYUV->linesize[2] = bmp->pitches[1]; - // sws_scale(img_convert_ctx, - // (const unsigned char *const *)pFrame->data, - // pFrame->linesize, 0, pCodecCtx->height, - // pFrameYUV->data, pFrameYUV->linesize); - - // #if OUTPUT_YUV420P - // int y_size = pCodecCtx->width * pCodecCtx->height; - // fwrite(pFrameYUV->data[0], 1, y_size, fp_yuv); // Y - // fwrite(pFrameYUV->data[1], 1, y_size / 4, fp_yuv); // - // U fwrite(pFrameYUV->data[2], 1, y_size / 4, fp_yuv); - // // V - // #endif - // SDL_UnlockYUVOverlay(bmp); - - // SDL_DisplayYUVOverlay(bmp, &rect); - - // YUV420ToNV12FFmpeg(buffer, pixel_w, pixel_h, dst_buffer); - - // SDL_UpdateTexture(sdlTexture, NULL, dst_buffer, pixel_w); - - // // FIX: If window is resize - // sdlRect.x = 0; - // sdlRect.y = 0; - // sdlRect.w = screen_w; - // sdlRect.h = screen_h; - - // SDL_RenderClear(sdlRenderer); - // SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect); - // SDL_RenderPresent(sdlRenderer); - } - } - // av_free_packet(packet); - } else { - // Exit Thread - thread_exit = 1; - } - } else if (event.type == SDL_QUIT) { - thread_exit = 1; - } else if (event.type == SFM_BREAK_EVENT) { - break; - } - } - - sws_freeContext(img_convert_ctx); - -#if OUTPUT_YUV420P - fclose(fp_yuv); -#endif - - SDL_Quit(); - - // av_free(out_buffer); - av_free(pFrameYUV); - avcodec_close(pCodecCtx); - avformat_close_input(&pFormatCtx); - - return 0; -} \ No newline at end of file diff --git a/remote_desk_server/main.cpp b/remote_desk_server/main.cpp new file mode 100644 index 0000000..c771b74 --- /dev/null +++ b/remote_desk_server/main.cpp @@ -0,0 +1,12 @@ +#include + +#include "remote_desk_server.h" + +int main() { + RemoteDeskServer remote_desk_server; + remote_desk_server.Init(); + + while (1) { + } + return 0; +} \ No newline at end of file diff --git a/remote_desk_server/remote_desk_server.cpp b/remote_desk_server/remote_desk_server.cpp new file mode 100644 index 0000000..1f2f03c --- /dev/null +++ b/remote_desk_server/remote_desk_server.cpp @@ -0,0 +1,93 @@ +#include "remote_desk_server.h" + +#include + +extern "C" { +#include +#include +#include +}; + +#define NV12_BUFFER_SIZE 2560 * 1440 * 3 / 2 + +RemoteDeskServer ::RemoteDeskServer() {} + +RemoteDeskServer ::~RemoteDeskServer() { + if (nv12_buffer_) { + delete nv12_buffer_; + nv12_buffer_ = nullptr; + } +} + +int BGRAToNV12FFmpeg(unsigned char *src_buffer, int width, int height, + unsigned char *dst_buffer) { + AVFrame *Input_pFrame = av_frame_alloc(); + AVFrame *Output_pFrame = av_frame_alloc(); + struct SwsContext *img_convert_ctx = sws_getContext( + width, height, AV_PIX_FMT_BGRA, width, height, AV_PIX_FMT_NV12, + SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); + + av_image_fill_arrays(Input_pFrame->data, Input_pFrame->linesize, src_buffer, + AV_PIX_FMT_BGRA, width, height, 1); + av_image_fill_arrays(Output_pFrame->data, Output_pFrame->linesize, dst_buffer, + AV_PIX_FMT_NV12, width, height, 1); + + sws_scale(img_convert_ctx, (uint8_t const **)Input_pFrame->data, + Input_pFrame->linesize, 0, height, Output_pFrame->data, + Output_pFrame->linesize); + + if (Input_pFrame) av_free(Input_pFrame); + if (Output_pFrame) av_free(Output_pFrame); + if (img_convert_ctx) sws_freeContext(img_convert_ctx); + + return 0; +} + +void RemoteDeskServer::HostReceiveBuffer(const char *data, size_t size, + const char *user_id, + size_t user_id_size) { + std::string msg(data, size); + std::string user(user_id, user_id_size); + + std::cout << "Receive: [" << user << "] " << msg << std::endl; +} + +int RemoteDeskServer::Init() { + Params params; + params.cfg_path = "../../../../config/config.ini"; + params.on_receive_buffer = [](const char *data, size_t size, + const char *user_id, size_t user_id_size) { + // std::string msg(data, size); + // std::string user(user_id, user_id_size); + + // std::cout << "Receive: [" << user << "] " << msg << std::endl; + }; + + std::string transmission_id = "000000"; + std::string user_id = "Server"; + peer = CreatePeer(¶ms); + CreateConnection(peer, transmission_id.c_str(), user_id.c_str()); + + nv12_buffer_ = new char[NV12_BUFFER_SIZE]; + + screen_capture = new ScreenCaptureWgc(); + + RECORD_DESKTOP_RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = GetSystemMetrics(SM_CXSCREEN); + rect.bottom = GetSystemMetrics(SM_CYSCREEN); + + screen_capture->Init( + rect, 60, + [this](unsigned char *data, int size, int width, int height) -> void { + // std::cout << "Send" << std::endl; + BGRAToNV12FFmpeg(data, width, height, (unsigned char *)nv12_buffer_); + SendData(peer, DATA_TYPE::VIDEO, (const char *)nv12_buffer_, + NV12_BUFFER_SIZE); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + }); + + screen_capture->Start(); + return 0; +} \ No newline at end of file diff --git a/remote_desk_server/remote_desk_server.h b/remote_desk_server/remote_desk_server.h new file mode 100644 index 0000000..8141e5d --- /dev/null +++ b/remote_desk_server/remote_desk_server.h @@ -0,0 +1,25 @@ +#ifndef _REMOTE_DESK_SERVER_H_ +#define _REMOTE_DESK_SERVER_H_ + +#include "screen_capture_wgc.h" +#include "x.h" + +class RemoteDeskServer { + public: + RemoteDeskServer(); + ~RemoteDeskServer(); + + public: + int Init(); + + static void HostReceiveBuffer(const char* data, size_t size, + const char* user_id, size_t user_id_size); + + private: + PeerPtr* peer = nullptr; + ScreenCaptureWgc* screen_capture = nullptr; + + char* nv12_buffer_ = nullptr; +}; + +#endif \ No newline at end of file diff --git a/dll/main.cpp b/screen_capture/main.cpp.bak similarity index 97% rename from dll/main.cpp rename to screen_capture/main.cpp.bak index f2a1f18..7c3d838 100644 --- a/dll/main.cpp +++ b/screen_capture/main.cpp.bak @@ -19,9 +19,7 @@ extern "C" { int screen_w = 2560, screen_h = 1440; const int pixel_w = 2560, pixel_h = 1440; -unsigned char buffer[pixel_w * pixel_h * 3 / 2]; unsigned char dst_buffer[pixel_w * pixel_h * 3 / 2]; -unsigned char rgbData[pixel_w * pixel_h * 4]; SDL_Texture *sdlTexture = nullptr; SDL_Renderer *sdlRenderer = nullptr; SDL_Rect sdlRect; diff --git a/dll/screen_capture_wgc.cpp b/screen_capture/screen_capture_wgc.cpp similarity index 54% rename from dll/screen_capture_wgc.cpp rename to screen_capture/screen_capture_wgc.cpp index 448a68c..f27f045 100644 --- a/dll/screen_capture_wgc.cpp +++ b/screen_capture/screen_capture_wgc.cpp @@ -55,10 +55,7 @@ int ScreenCaptureWgc::Init(const RECORD_DESKTOP_RECT &rect, const int fps, if (_inited == true) return error; _fps = fps; - _rect = rect; - _start_time = av_gettime_relative(); - _time_base = {1, AV_TIME_BASE}; - _pixel_fmt = AV_PIX_FMT_BGRA; + _on_data = cb; do { @@ -126,71 +123,9 @@ int ScreenCaptureWgc::Stop() { } void ScreenCaptureWgc::OnFrame(const WgcSession::wgc_session_frame &frame) { - // std::cout << "onframe" << std::endl; - // AVFrame *av_frame = av_frame_alloc(); - - // av_frame->pts = av_gettime_relative(); - // av_frame->pkt_dts = av_frame->pts; - // // av_frame->pkt_pts = av_frame->pts; - - // av_frame->width = frame.width; - // av_frame->height = frame.height; - // av_frame->format = AV_PIX_FMT_BGRA; - // av_frame->pict_type = AV_PICTURE_TYPE_NONE; - // av_frame->pkt_size = frame.width * frame.height * 4; - - // av_image_fill_arrays(av_frame->data, av_frame->linesize, frame.data, - // AV_PIX_FMT_BGRA, frame.width, frame.height, 1); - if (_on_data) _on_data((unsigned char *)frame.data, frame.width * frame.height * 4, frame.width, frame.height); - - // av_frame_free(&av_frame); - - // BGRA to YUV - // auto swrCtxBGRA2YUV = sws_getContext( - // frame.width, frame.height, AV_PIX_FMT_BGRA, frame.width, frame.height, - // AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); - - // create BGRA - // AVFrame *frame_bgra = av_frame; - // AVFrame *frame_bgra = av_frame_alloc(); - // frame_bgra->format = AV_PIX_FMT_BGRA; - // frame_bgra->width = frame.width; - // frame_bgra->height = frame.height; - // if (av_frame_get_buffer(frame_bgra, 32) < 0) { - // printf("Failed: av_frame_get_buffer\n"); - // return; - // } - // frame_bgra->data[0] = cropImage; - - // YUV - // AVFrame *frame_yuv = av_frame_alloc(); - // frame_yuv->width = frame.width; - // frame_yuv->height = frame.height; - // frame_yuv->format = AV_PIX_FMT_YUV420P; - - // uint8_t *picture_buf = - // (uint8_t *)av_malloc(frame.width * frame.height * 3 / 2); - // if (av_image_fill_arrays(frame_yuv->data, frame_yuv->linesize, picture_buf, - // AV_PIX_FMT_YUV420P, frame.width, frame.height, - // 1) < 0) { - // std::cout << "Failed: av_image_fill_arrays" << std::endl; - // return; - // } - - // if (sws_scale(swrCtxBGRA2YUV, frame_bgra->data, frame_bgra->linesize, 0, - // frame.height, frame_yuv->data, frame_yuv->linesize) < 0) { - // std::cout << "BGRA to YUV failed" << std::endl; - // return; - // } - - // frame_yuv->pts = av_gettime(); - - // if (_on_data) - // _on_data((unsigned char *)frame_yuv->data, - // frame.width * frame.height * 3 / 2, frame.width, frame.height); } void ScreenCaptureWgc::CleanUp() { diff --git a/dll/screen_capture_wgc.h b/screen_capture/screen_capture_wgc.h similarity index 79% rename from dll/screen_capture_wgc.h rename to screen_capture/screen_capture_wgc.h index 6a5ab86..5358234 100644 --- a/dll/screen_capture_wgc.h +++ b/screen_capture/screen_capture_wgc.h @@ -3,23 +3,14 @@ #include -#include "wgc_session.h" -#include "wgc_session_impl.h" - -extern "C" { -#include -#include -#include -#include -#include -#include -} - #include #include #include #include +#include "wgc_session.h" +#include "wgc_session_impl.h" + typedef struct { int left; int top; @@ -67,10 +58,6 @@ class ScreenCaptureWgc : public WgcSession::wgc_session_observer { cb_desktop_data _on_data; cb_desktop_error _on_error; - - AVRational _time_base; - int64_t _start_time; - AVPixelFormat _pixel_fmt; }; #endif \ No newline at end of file diff --git a/dll/wgc_session.h b/screen_capture/wgc_session.h similarity index 100% rename from dll/wgc_session.h rename to screen_capture/wgc_session.h diff --git a/dll/wgc_session_impl.cpp b/screen_capture/wgc_session_impl.cpp similarity index 100% rename from dll/wgc_session_impl.cpp rename to screen_capture/wgc_session_impl.cpp diff --git a/dll/wgc_session_impl.h b/screen_capture/wgc_session_impl.h similarity index 100% rename from dll/wgc_session_impl.h rename to screen_capture/wgc_session_impl.h diff --git a/webrtc/wgc_capture_session.cc b/webrtc/wgc_capture_session.cc deleted file mode 100644 index a577a84..0000000 --- a/webrtc/wgc_capture_session.cc +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "modules/desktop_capture/win/wgc_capture_session.h" - -#include -#include -#include - -#include -#include -#include - -#include "modules/desktop_capture/win/wgc_desktop_frame.h" -#include "rtc_base/checks.h" -#include "rtc_base/logging.h" -#include "rtc_base/time_utils.h" -#include "rtc_base/win/create_direct3d_device.h" -#include "rtc_base/win/get_activation_factory.h" -#include "system_wrappers/include/metrics.h" - -using Microsoft::WRL::ComPtr; -namespace WGC = ABI::Windows::Graphics::Capture; - -namespace webrtc { -namespace { - -// We must use a BGRA pixel format that has 4 bytes per pixel, as required by -// the DesktopFrame interface. -const auto kPixelFormat = ABI::Windows::Graphics::DirectX::DirectXPixelFormat:: - DirectXPixelFormat_B8G8R8A8UIntNormalized; - -// We only want 1 buffer in our frame pool to reduce latency. If we had more, -// they would sit in the pool for longer and be stale by the time we are asked -// for a new frame. -const int kNumBuffers = 1; - -// These values are persisted to logs. Entries should not be renumbered and -// numeric values should never be reused. -enum class StartCaptureResult { - kSuccess = 0, - kSourceClosed = 1, - kAddClosedFailed = 2, - kDxgiDeviceCastFailed = 3, - kD3dDelayLoadFailed = 4, - kD3dDeviceCreationFailed = 5, - kFramePoolActivationFailed = 6, - kFramePoolCastFailed = 7, - kGetItemSizeFailed = 8, - kCreateFreeThreadedFailed = 9, - kCreateCaptureSessionFailed = 10, - kStartCaptureFailed = 11, - kMaxValue = kStartCaptureFailed -}; - -// These values are persisted to logs. Entries should not be renumbered and -// numeric values should never be reused. -enum class GetFrameResult { - kSuccess = 0, - kItemClosed = 1, - kTryGetNextFrameFailed = 2, - kFrameDropped = 3, - kGetSurfaceFailed = 4, - kDxgiInterfaceAccessFailed = 5, - kTexture2dCastFailed = 6, - kCreateMappedTextureFailed = 7, - kMapFrameFailed = 8, - kGetContentSizeFailed = 9, - kResizeMappedTextureFailed = 10, - kRecreateFramePoolFailed = 11, - kMaxValue = kRecreateFramePoolFailed -}; - -void RecordStartCaptureResult(StartCaptureResult error) { - RTC_HISTOGRAM_ENUMERATION( - "WebRTC.DesktopCapture.Win.WgcCaptureSessionStartResult", - static_cast(error), static_cast(StartCaptureResult::kMaxValue)); -} - -void RecordGetFrameResult(GetFrameResult error) { - RTC_HISTOGRAM_ENUMERATION( - "WebRTC.DesktopCapture.Win.WgcCaptureSessionGetFrameResult", - static_cast(error), static_cast(GetFrameResult::kMaxValue)); -} - -} // namespace - -WgcCaptureSession::WgcCaptureSession(ComPtr d3d11_device, - ComPtr item) - : d3d11_device_(std::move(d3d11_device)), item_(std::move(item)) {} -WgcCaptureSession::~WgcCaptureSession() = default; - -HRESULT WgcCaptureSession::StartCapture() { - RTC_DCHECK_RUN_ON(&sequence_checker_); - RTC_DCHECK(!is_capture_started_); - - if (item_closed_) { - RTC_LOG(LS_ERROR) << "The target source has been closed."; - RecordStartCaptureResult(StartCaptureResult::kSourceClosed); - return E_ABORT; - } - - RTC_DCHECK(d3d11_device_); - RTC_DCHECK(item_); - - // Listen for the Closed event, to detect if the source we are capturing is - // closed (e.g. application window is closed or monitor is disconnected). If - // it is, we should abort the capture. - auto closed_handler = - Microsoft::WRL::Callback>( - this, &WgcCaptureSession::OnItemClosed); - EventRegistrationToken item_closed_token; - HRESULT hr = item_->add_Closed(closed_handler.Get(), &item_closed_token); - if (FAILED(hr)) { - RecordStartCaptureResult(StartCaptureResult::kAddClosedFailed); - return hr; - } - - ComPtr dxgi_device; - hr = d3d11_device_->QueryInterface(IID_PPV_ARGS(&dxgi_device)); - if (FAILED(hr)) { - RecordStartCaptureResult(StartCaptureResult::kDxgiDeviceCastFailed); - return hr; - } - - if (!ResolveCoreWinRTDirect3DDelayload()) { - RecordStartCaptureResult(StartCaptureResult::kD3dDelayLoadFailed); - return E_FAIL; - } - - hr = CreateDirect3DDeviceFromDXGIDevice(dxgi_device.Get(), &direct3d_device_); - if (FAILED(hr)) { - RecordStartCaptureResult(StartCaptureResult::kD3dDeviceCreationFailed); - return hr; - } - - ComPtr frame_pool_statics; - hr = GetActivationFactory< - ABI::Windows::Graphics::Capture::IDirect3D11CaptureFramePoolStatics, - RuntimeClass_Windows_Graphics_Capture_Direct3D11CaptureFramePool>( - &frame_pool_statics); - if (FAILED(hr)) { - RecordStartCaptureResult(StartCaptureResult::kFramePoolActivationFailed); - return hr; - } - - // Cast to FramePoolStatics2 so we can use CreateFreeThreaded and avoid the - // need to have a DispatcherQueue. We don't listen for the FrameArrived event, - // so there's no difference. - ComPtr frame_pool_statics2; - hr = frame_pool_statics->QueryInterface(IID_PPV_ARGS(&frame_pool_statics2)); - if (FAILED(hr)) { - RecordStartCaptureResult(StartCaptureResult::kFramePoolCastFailed); - return hr; - } - - ABI::Windows::Graphics::SizeInt32 item_size; - hr = item_.Get()->get_Size(&item_size); - if (FAILED(hr)) { - RecordStartCaptureResult(StartCaptureResult::kGetItemSizeFailed); - return hr; - } - - previous_size_ = item_size; - - hr = frame_pool_statics2->CreateFreeThreaded(direct3d_device_.Get(), - kPixelFormat, kNumBuffers, - item_size, &frame_pool_); - if (FAILED(hr)) { - RecordStartCaptureResult(StartCaptureResult::kCreateFreeThreadedFailed); - return hr; - } - - hr = frame_pool_->CreateCaptureSession(item_.Get(), &session_); - if (FAILED(hr)) { - RecordStartCaptureResult(StartCaptureResult::kCreateCaptureSessionFailed); - return hr; - } - - hr = session_->StartCapture(); - if (FAILED(hr)) { - RTC_LOG(LS_ERROR) << "Failed to start CaptureSession: " << hr; - RecordStartCaptureResult(StartCaptureResult::kStartCaptureFailed); - return hr; - } - - RecordStartCaptureResult(StartCaptureResult::kSuccess); - - is_capture_started_ = true; - return hr; -} - -HRESULT WgcCaptureSession::GetFrame( - std::unique_ptr* output_frame) { - RTC_DCHECK_RUN_ON(&sequence_checker_); - - if (item_closed_) { - RTC_LOG(LS_ERROR) << "The target source has been closed."; - RecordGetFrameResult(GetFrameResult::kItemClosed); - return E_ABORT; - } - - RTC_DCHECK(is_capture_started_); - - ComPtr capture_frame; - HRESULT hr = frame_pool_->TryGetNextFrame(&capture_frame); - if (FAILED(hr)) { - RTC_LOG(LS_ERROR) << "TryGetNextFrame failed: " << hr; - RecordGetFrameResult(GetFrameResult::kTryGetNextFrameFailed); - return hr; - } - - if (!capture_frame) { - RecordGetFrameResult(GetFrameResult::kFrameDropped); - return hr; - } - - // We need to get this CaptureFrame as an ID3D11Texture2D so that we can get - // the raw image data in the format required by the DesktopFrame interface. - ComPtr - d3d_surface; - hr = capture_frame->get_Surface(&d3d_surface); - if (FAILED(hr)) { - RecordGetFrameResult(GetFrameResult::kGetSurfaceFailed); - return hr; - } - - ComPtr - direct3DDxgiInterfaceAccess; - hr = d3d_surface->QueryInterface(IID_PPV_ARGS(&direct3DDxgiInterfaceAccess)); - if (FAILED(hr)) { - RecordGetFrameResult(GetFrameResult::kDxgiInterfaceAccessFailed); - return hr; - } - - ComPtr texture_2D; - hr = direct3DDxgiInterfaceAccess->GetInterface(IID_PPV_ARGS(&texture_2D)); - if (FAILED(hr)) { - RecordGetFrameResult(GetFrameResult::kTexture2dCastFailed); - return hr; - } - - if (!mapped_texture_) { - hr = CreateMappedTexture(texture_2D); - if (FAILED(hr)) { - RecordGetFrameResult(GetFrameResult::kCreateMappedTextureFailed); - return hr; - } - } - - // We need to copy |texture_2D| into |mapped_texture_| as the latter has the - // D3D11_CPU_ACCESS_READ flag set, which lets us access the image data. - // Otherwise it would only be readable by the GPU. - ComPtr d3d_context; - d3d11_device_->GetImmediateContext(&d3d_context); - d3d_context->CopyResource(mapped_texture_.Get(), texture_2D.Get()); - - D3D11_MAPPED_SUBRESOURCE map_info; - hr = d3d_context->Map(mapped_texture_.Get(), /*subresource_index=*/0, - D3D11_MAP_READ, /*D3D11_MAP_FLAG_DO_NOT_WAIT=*/0, - &map_info); - if (FAILED(hr)) { - RecordGetFrameResult(GetFrameResult::kMapFrameFailed); - return hr; - } - - ABI::Windows::Graphics::SizeInt32 new_size; - hr = capture_frame->get_ContentSize(&new_size); - if (FAILED(hr)) { - RecordGetFrameResult(GetFrameResult::kGetContentSizeFailed); - return hr; - } - - // If the size has changed since the last capture, we must be sure to use - // the smaller dimensions. Otherwise we might overrun our buffer, or - // read stale data from the last frame. - int image_height = std::min(previous_size_.Height, new_size.Height); - int image_width = std::min(previous_size_.Width, new_size.Width); - int row_data_length = image_width * DesktopFrame::kBytesPerPixel; - - // Make a copy of the data pointed to by |map_info.pData| so we are free to - // unmap our texture. - uint8_t* src_data = static_cast(map_info.pData); - std::vector image_data; - image_data.reserve(image_height * row_data_length); - uint8_t* image_data_ptr = image_data.data(); - for (int i = 0; i < image_height; i++) { - memcpy(image_data_ptr, src_data, row_data_length); - image_data_ptr += row_data_length; - src_data += map_info.RowPitch; - } - - // Transfer ownership of |image_data| to the output_frame. - DesktopSize size(image_width, image_height); - *output_frame = std::make_unique(size, row_data_length, - std::move(image_data)); - - d3d_context->Unmap(mapped_texture_.Get(), 0); - - // If the size changed, we must resize the texture and frame pool to fit the - // new size. - if (previous_size_.Height != new_size.Height || - previous_size_.Width != new_size.Width) { - hr = CreateMappedTexture(texture_2D, new_size.Width, new_size.Height); - if (FAILED(hr)) { - RecordGetFrameResult(GetFrameResult::kResizeMappedTextureFailed); - return hr; - } - - hr = frame_pool_->Recreate(direct3d_device_.Get(), kPixelFormat, - kNumBuffers, new_size); - if (FAILED(hr)) { - RecordGetFrameResult(GetFrameResult::kRecreateFramePoolFailed); - return hr; - } - } - - RecordGetFrameResult(GetFrameResult::kSuccess); - - previous_size_ = new_size; - return hr; -} - -HRESULT WgcCaptureSession::CreateMappedTexture( - ComPtr src_texture, - UINT width, - UINT height) { - RTC_DCHECK_RUN_ON(&sequence_checker_); - - D3D11_TEXTURE2D_DESC src_desc; - src_texture->GetDesc(&src_desc); - D3D11_TEXTURE2D_DESC map_desc; - map_desc.Width = width == 0 ? src_desc.Width : width; - map_desc.Height = height == 0 ? src_desc.Height : height; - map_desc.MipLevels = src_desc.MipLevels; - map_desc.ArraySize = src_desc.ArraySize; - map_desc.Format = src_desc.Format; - map_desc.SampleDesc = src_desc.SampleDesc; - map_desc.Usage = D3D11_USAGE_STAGING; - map_desc.BindFlags = 0; - map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - map_desc.MiscFlags = 0; - return d3d11_device_->CreateTexture2D(&map_desc, nullptr, &mapped_texture_); -} - -HRESULT WgcCaptureSession::OnItemClosed(WGC::IGraphicsCaptureItem* sender, - IInspectable* event_args) { - RTC_DCHECK_RUN_ON(&sequence_checker_); - - RTC_LOG(LS_INFO) << "Capture target has been closed."; - item_closed_ = true; - is_capture_started_ = false; - - mapped_texture_ = nullptr; - session_ = nullptr; - frame_pool_ = nullptr; - direct3d_device_ = nullptr; - item_ = nullptr; - d3d11_device_ = nullptr; - - return S_OK; -} - -} // namespace webrtc diff --git a/webrtc/wgc_capture_session.h b/webrtc/wgc_capture_session.h deleted file mode 100644 index a392971..0000000 --- a/webrtc/wgc_capture_session.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURE_SESSION_H_ -#define MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURE_SESSION_H_ - -#include -#include -#include - -#include - -#include "api/sequence_checker.h" -#include "modules/desktop_capture/desktop_capture_options.h" -#include "modules/desktop_capture/win/wgc_capture_source.h" - -namespace webrtc { - -class WgcCaptureSession final { - public: - WgcCaptureSession( - Microsoft::WRL::ComPtr d3d11_device, - Microsoft::WRL::ComPtr< - ABI::Windows::Graphics::Capture::IGraphicsCaptureItem> item); - - // Disallow copy and assign. - WgcCaptureSession(const WgcCaptureSession&) = delete; - WgcCaptureSession& operator=(const WgcCaptureSession&) = delete; - - ~WgcCaptureSession(); - - HRESULT StartCapture(); - - // Returns a frame from the frame pool, if any are present. - HRESULT GetFrame(std::unique_ptr* output_frame); - - bool IsCaptureStarted() const { - RTC_DCHECK_RUN_ON(&sequence_checker_); - return is_capture_started_; - } - - private: - // Initializes |mapped_texture_| with the properties of the |src_texture|, - // overrides the values of some necessary properties like the - // D3D11_CPU_ACCESS_READ flag. Also has optional parameters for what size - // |mapped_texture_| should be, if they aren't provided we will use the size - // of |src_texture|. - HRESULT CreateMappedTexture( - Microsoft::WRL::ComPtr src_texture, - UINT width = 0, - UINT height = 0); - - // Event handler for |item_|'s Closed event. - HRESULT OnItemClosed( - ABI::Windows::Graphics::Capture::IGraphicsCaptureItem* sender, - IInspectable* event_args); - - // A Direct3D11 Device provided by the caller. We use this to create an - // IDirect3DDevice, and also to create textures that will hold the image data. - Microsoft::WRL::ComPtr d3d11_device_; - - // This item represents what we are capturing, we use it to create the - // capture session, and also to listen for the Closed event. - Microsoft::WRL::ComPtr - item_; - - // The IDirect3DDevice is necessary to instantiate the frame pool. - Microsoft::WRL::ComPtr< - ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice> - direct3d_device_; - - // The frame pool is where frames are deposited during capture, we retrieve - // them from here with TryGetNextFrame(). - Microsoft::WRL::ComPtr< - ABI::Windows::Graphics::Capture::IDirect3D11CaptureFramePool> - frame_pool_; - - // This texture holds the final image data. We made it a member so we can - // reuse it, instead of having to create a new texture every time we grab a - // frame. - Microsoft::WRL::ComPtr mapped_texture_; - - // This lets us know when the source has been resized, which is important - // because we must resize the framepool and our texture to be able to hold - // enough data for the frame. - ABI::Windows::Graphics::SizeInt32 previous_size_; - - // The capture session lets us set properties about the capture before it - // starts such as whether to capture the mouse cursor, and it lets us tell WGC - // to start capturing frames. - Microsoft::WRL::ComPtr< - ABI::Windows::Graphics::Capture::IGraphicsCaptureSession> - session_; - - bool item_closed_ = false; - bool is_capture_started_ = false; - - SequenceChecker sequence_checker_; -}; - -} // namespace webrtc - -#endif // MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURE_SESSION_H_ diff --git a/webrtc/wgc_capture_source.cc b/webrtc/wgc_capture_source.cc deleted file mode 100644 index 0532bd4..0000000 --- a/webrtc/wgc_capture_source.cc +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#include "modules/desktop_capture/win/wgc_capture_source.h" -#include -#include -#include -#include "modules/desktop_capture/win/screen_capture_utils.h" -#include "modules/desktop_capture/win/window_capture_utils.h" -#include "rtc_base/win/get_activation_factory.h" -using Microsoft::WRL::ComPtr; -namespace WGC = ABI::Windows::Graphics::Capture; -namespace webrtc { -WgcCaptureSource::WgcCaptureSource(DesktopCapturer::SourceId source_id) - : source_id_(source_id) {} -WgcCaptureSource::~WgcCaptureSource() = default; -bool WgcCaptureSource::IsCapturable() { - // If we can create a capture item, then we can capture it. Unfortunately, - // we can't cache this item because it may be created in a different COM - // apartment than where capture will eventually start from. - ComPtr item; - return SUCCEEDED(CreateCaptureItem(&item)); -} -bool WgcCaptureSource::FocusOnSource() { - return false; -} -HRESULT WgcCaptureSource::GetCaptureItem( - ComPtr* result) { - HRESULT hr = S_OK; - if (!item_) - hr = CreateCaptureItem(&item_); - *result = item_; - return hr; -} -WgcCaptureSourceFactory::~WgcCaptureSourceFactory() = default; -WgcWindowSourceFactory::WgcWindowSourceFactory() = default; -WgcWindowSourceFactory::~WgcWindowSourceFactory() = default; -std::unique_ptr WgcWindowSourceFactory::CreateCaptureSource( - DesktopCapturer::SourceId source_id) { - return std::make_unique(source_id); -} -WgcScreenSourceFactory::WgcScreenSourceFactory() = default; -WgcScreenSourceFactory::~WgcScreenSourceFactory() = default; -std::unique_ptr WgcScreenSourceFactory::CreateCaptureSource( - DesktopCapturer::SourceId source_id) { - return std::make_unique(source_id); -} -WgcWindowSource::WgcWindowSource(DesktopCapturer::SourceId source_id) - : WgcCaptureSource(source_id) {} -WgcWindowSource::~WgcWindowSource() = default; -DesktopVector WgcWindowSource::GetTopLeft() { - DesktopRect window_rect; - if (!GetWindowRect(reinterpret_cast(GetSourceId()), &window_rect)) - return DesktopVector(); - return window_rect.top_left(); -} -bool WgcWindowSource::IsCapturable() { - if (!IsWindowValidAndVisible(reinterpret_cast(GetSourceId()))) - return false; - return WgcCaptureSource::IsCapturable(); -} -bool WgcWindowSource::FocusOnSource() { - if (!IsWindowValidAndVisible(reinterpret_cast(GetSourceId()))) - return false; - return ::BringWindowToTop(reinterpret_cast(GetSourceId())) && - ::SetForegroundWindow(reinterpret_cast(GetSourceId())); -} -HRESULT WgcWindowSource::CreateCaptureItem( - ComPtr* result) { - if (!ResolveCoreWinRTDelayload()) - return E_FAIL; - ComPtr interop; - HRESULT hr = GetActivationFactory< - IGraphicsCaptureItemInterop, - RuntimeClass_Windows_Graphics_Capture_GraphicsCaptureItem>(&interop); - if (FAILED(hr)) - return hr; - ComPtr item; - hr = interop->CreateForWindow(reinterpret_cast(GetSourceId()), - IID_PPV_ARGS(&item)); - if (FAILED(hr)) - return hr; - if (!item) - return E_HANDLE; - *result = std::move(item); - return hr; -} -WgcScreenSource::WgcScreenSource(DesktopCapturer::SourceId source_id) - : WgcCaptureSource(source_id) { - // Getting the HMONITOR could fail if the source_id is invalid. In that case, - // we leave hmonitor_ uninitialized and |IsCapturable()| will fail. - HMONITOR hmon; - if (GetHmonitorFromDeviceIndex(GetSourceId(), &hmon)) - hmonitor_ = hmon; -} -WgcScreenSource::~WgcScreenSource() = default; -DesktopVector WgcScreenSource::GetTopLeft() { - if (!hmonitor_) - return DesktopVector(); - return GetMonitorRect(*hmonitor_).top_left(); -} -bool WgcScreenSource::IsCapturable() { - if (!hmonitor_) - return false; - if (!IsMonitorValid(*hmonitor_)) - return false; - return WgcCaptureSource::IsCapturable(); -} -HRESULT WgcScreenSource::CreateCaptureItem( - ComPtr* result) { - if (!hmonitor_) - return E_ABORT; - if (!ResolveCoreWinRTDelayload()) - return E_FAIL; - ComPtr interop; - HRESULT hr = GetActivationFactory< - IGraphicsCaptureItemInterop, - RuntimeClass_Windows_Graphics_Capture_GraphicsCaptureItem>(&interop); - if (FAILED(hr)) - return hr; - ComPtr item; - hr = interop->CreateForMonitor(*hmonitor_, IID_PPV_ARGS(&item)); - if (FAILED(hr)) - return hr; - if (!item) - return E_HANDLE; - *result = std::move(item); - return hr; -} -} // namespace webrtc diff --git a/webrtc/wgc_capture_source.h b/webrtc/wgc_capture_source.h deleted file mode 100644 index 04e4519..0000000 --- a/webrtc/wgc_capture_source.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#ifndef MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURE_SOURCE_H_ -#define MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURE_SOURCE_H_ -#include -#include -#include -#include "absl/types/optional.h" -#include "modules/desktop_capture/desktop_capturer.h" -#include "modules/desktop_capture/desktop_geometry.h" -namespace webrtc { -// Abstract class to represent the source that WGC-based capturers capture -// from. Could represent an application window or a screen. Consumers should use -// the appropriate Wgc*SourceFactory class to create WgcCaptureSource objects -// of the appropriate type. -class WgcCaptureSource { - public: - explicit WgcCaptureSource(DesktopCapturer::SourceId source_id); - virtual ~WgcCaptureSource(); - virtual DesktopVector GetTopLeft() = 0; - virtual bool IsCapturable(); - virtual bool FocusOnSource(); - HRESULT GetCaptureItem( - Microsoft::WRL::ComPtr< - ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>* result); - DesktopCapturer::SourceId GetSourceId() { return source_id_; } - protected: - virtual HRESULT CreateCaptureItem( - Microsoft::WRL::ComPtr< - ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>* result) = 0; - private: - Microsoft::WRL::ComPtr - item_; - const DesktopCapturer::SourceId source_id_; -}; -class WgcCaptureSourceFactory { - public: - virtual ~WgcCaptureSourceFactory(); - virtual std::unique_ptr CreateCaptureSource( - DesktopCapturer::SourceId) = 0; -}; -class WgcWindowSourceFactory final : public WgcCaptureSourceFactory { - public: - WgcWindowSourceFactory(); - // Disallow copy and assign. - WgcWindowSourceFactory(const WgcWindowSourceFactory&) = delete; - WgcWindowSourceFactory& operator=(const WgcWindowSourceFactory&) = delete; - ~WgcWindowSourceFactory() override; - std::unique_ptr CreateCaptureSource( - DesktopCapturer::SourceId) override; -}; -class WgcScreenSourceFactory final : public WgcCaptureSourceFactory { - public: - WgcScreenSourceFactory(); - WgcScreenSourceFactory(const WgcScreenSourceFactory&) = delete; - WgcScreenSourceFactory& operator=(const WgcScreenSourceFactory&) = delete; - ~WgcScreenSourceFactory() override; - std::unique_ptr CreateCaptureSource( - DesktopCapturer::SourceId) override; -}; -// Class for capturing application windows. -class WgcWindowSource final : public WgcCaptureSource { - public: - explicit WgcWindowSource(DesktopCapturer::SourceId source_id); - WgcWindowSource(const WgcWindowSource&) = delete; - WgcWindowSource& operator=(const WgcWindowSource&) = delete; - ~WgcWindowSource() override; - DesktopVector GetTopLeft() override; - bool IsCapturable() override; - bool FocusOnSource() override; - private: - HRESULT CreateCaptureItem( - Microsoft::WRL::ComPtr< - ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>* result) - override; -}; -// Class for capturing screens/monitors/displays. -class WgcScreenSource final : public WgcCaptureSource { - public: - explicit WgcScreenSource(DesktopCapturer::SourceId source_id); - WgcScreenSource(const WgcScreenSource&) = delete; - WgcScreenSource& operator=(const WgcScreenSource&) = delete; - ~WgcScreenSource() override; - DesktopVector GetTopLeft() override; - bool IsCapturable() override; - private: - HRESULT CreateCaptureItem( - Microsoft::WRL::ComPtr< - ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>* result) - override; - // To maintain compatibility with other capturers, this class accepts a - // device index as it's SourceId. However, WGC requires we use an HMONITOR to - // describe which screen to capture. So, we internally convert the supplied - // device index into an HMONITOR when |IsCapturable()| is called. - absl::optional hmonitor_; -}; -} // namespace webrtc -#endif // MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURE_SOURCE_H_ diff --git a/webrtc/wgc_capture_source_unittest.cc b/webrtc/wgc_capture_source_unittest.cc deleted file mode 100644 index fffcbfe..0000000 --- a/webrtc/wgc_capture_source_unittest.cc +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#include "modules/desktop_capture/win/wgc_capture_source.h" -#include -#include -#include -#include "modules/desktop_capture/desktop_capture_types.h" -#include "modules/desktop_capture/desktop_geometry.h" -#include "modules/desktop_capture/win/screen_capture_utils.h" -#include "modules/desktop_capture/win/test_support/test_window.h" -#include "rtc_base/checks.h" -#include "rtc_base/logging.h" -#include "rtc_base/win/scoped_com_initializer.h" -#include "rtc_base/win/windows_version.h" -#include "test/gtest.h" -namespace webrtc { -namespace { -const WCHAR kWindowTitle[] = L"WGC Capture Source Test Window"; -const int kFirstXCoord = 25; -const int kFirstYCoord = 50; -const int kSecondXCoord = 50; -const int kSecondYCoord = 75; -enum SourceType { kWindowSource = 0, kScreenSource = 1 }; -} // namespace -class WgcCaptureSourceTest : public ::testing::TestWithParam { - public: - void SetUp() override { - if (rtc::rtc_win::GetVersion() < rtc::rtc_win::Version::VERSION_WIN10_RS5) { - RTC_LOG(LS_INFO) - << "Skipping WgcCaptureSourceTests on Windows versions < RS5."; - GTEST_SKIP(); - } - com_initializer_ = - std::make_unique(ScopedCOMInitializer::kMTA); - ASSERT_TRUE(com_initializer_->Succeeded()); - } - void TearDown() override { - if (window_open_) { - DestroyTestWindow(window_info_); - } - } - void SetUpForWindowSource() { - window_info_ = CreateTestWindow(kWindowTitle); - window_open_ = true; - source_id_ = reinterpret_cast(window_info_.hwnd); - source_factory_ = std::make_unique(); - } - void SetUpForScreenSource() { - source_id_ = kFullDesktopScreenId; - source_factory_ = std::make_unique(); - } - protected: - std::unique_ptr com_initializer_; - std::unique_ptr source_factory_; - std::unique_ptr source_; - DesktopCapturer::SourceId source_id_; - WindowInfo window_info_; - bool window_open_ = false; -}; -// Window specific test -TEST_F(WgcCaptureSourceTest, WindowPosition) { - SetUpForWindowSource(); - source_ = source_factory_->CreateCaptureSource(source_id_); - ASSERT_TRUE(source_); - EXPECT_EQ(source_->GetSourceId(), source_id_); - MoveTestWindow(window_info_.hwnd, kFirstXCoord, kFirstYCoord); - DesktopVector source_vector = source_->GetTopLeft(); - EXPECT_EQ(source_vector.x(), kFirstXCoord); - EXPECT_EQ(source_vector.y(), kFirstYCoord); - MoveTestWindow(window_info_.hwnd, kSecondXCoord, kSecondYCoord); - source_vector = source_->GetTopLeft(); - EXPECT_EQ(source_vector.x(), kSecondXCoord); - EXPECT_EQ(source_vector.y(), kSecondYCoord); -} -// Screen specific test -TEST_F(WgcCaptureSourceTest, ScreenPosition) { - SetUpForScreenSource(); - source_ = source_factory_->CreateCaptureSource(source_id_); - ASSERT_TRUE(source_); - EXPECT_EQ(source_id_, source_->GetSourceId()); - DesktopRect screen_rect = GetFullscreenRect(); - DesktopVector source_vector = source_->GetTopLeft(); - EXPECT_EQ(source_vector.x(), screen_rect.left()); - EXPECT_EQ(source_vector.y(), screen_rect.top()); -} -// Source agnostic test -TEST_P(WgcCaptureSourceTest, CreateSource) { - if (GetParam() == SourceType::kWindowSource) { - SetUpForWindowSource(); - } else { - SetUpForScreenSource(); - } - source_ = source_factory_->CreateCaptureSource(source_id_); - ASSERT_TRUE(source_); - EXPECT_EQ(source_id_, source_->GetSourceId()); - EXPECT_TRUE(source_->IsCapturable()); - Microsoft::WRL::ComPtr - item; - EXPECT_TRUE(SUCCEEDED(source_->GetCaptureItem(&item))); - EXPECT_TRUE(item); -} -INSTANTIATE_TEST_SUITE_P(SourceAgnostic, - WgcCaptureSourceTest, - ::testing::Values(SourceType::kWindowSource, - SourceType::kScreenSource)); -} // namespace webrtc diff --git a/webrtc/wgc_capturer_win.cc b/webrtc/wgc_capturer_win.cc deleted file mode 100644 index 9b2cce4..0000000 --- a/webrtc/wgc_capturer_win.cc +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "modules/desktop_capture/win/wgc_capturer_win.h" - -#include - -#include "modules/desktop_capture/desktop_capture_metrics_helper.h" -#include "modules/desktop_capture/desktop_capture_types.h" -#include "modules/desktop_capture/win/wgc_desktop_frame.h" -#include "rtc_base/logging.h" -#include "rtc_base/time_utils.h" -#include "system_wrappers/include/metrics.h" - -namespace WGC = ABI::Windows::Graphics::Capture; -using Microsoft::WRL::ComPtr; - -namespace webrtc { - -namespace { - -enum class WgcCapturerResult { - kSuccess = 0, - kNoDirect3dDevice = 1, - kNoSourceSelected = 2, - kItemCreationFailure = 3, - kSessionStartFailure = 4, - kGetFrameFailure = 5, - kFrameDropped = 6, - kMaxValue = kFrameDropped -}; - -void RecordWgcCapturerResult(WgcCapturerResult error) { - RTC_HISTOGRAM_ENUMERATION("WebRTC.DesktopCapture.Win.WgcCapturerResult", - static_cast(error), - static_cast(WgcCapturerResult::kMaxValue)); -} - -} // namespace - -WgcCapturerWin::WgcCapturerWin( - std::unique_ptr source_factory, - std::unique_ptr source_enumerator) - : source_factory_(std::move(source_factory)), - source_enumerator_(std::move(source_enumerator)) {} -WgcCapturerWin::~WgcCapturerWin() = default; - -// static -std::unique_ptr WgcCapturerWin::CreateRawWindowCapturer( - const DesktopCaptureOptions& options) { - return std::make_unique( - std::make_unique(), - std::make_unique( - options.enumerate_current_process_windows())); -} - -// static -std::unique_ptr WgcCapturerWin::CreateRawScreenCapturer( - const DesktopCaptureOptions& options) { - return std::make_unique( - std::make_unique(), - std::make_unique()); -} - -bool WgcCapturerWin::GetSourceList(SourceList* sources) { - return source_enumerator_->FindAllSources(sources); -} - -bool WgcCapturerWin::SelectSource(DesktopCapturer::SourceId id) { - capture_source_ = source_factory_->CreateCaptureSource(id); - return capture_source_->IsCapturable(); -} - -bool WgcCapturerWin::FocusOnSelectedSource() { - if (!capture_source_) - return false; - - return capture_source_->FocusOnSource(); -} - -void WgcCapturerWin::Start(Callback* callback) { - RTC_DCHECK(!callback_); - RTC_DCHECK(callback); - RecordCapturerImpl(DesktopCapturerId::kWgcCapturerWin); - - callback_ = callback; - - // Create a Direct3D11 device to share amongst the WgcCaptureSessions. Many - // parameters are nullptr as the implemention uses defaults that work well for - // us. - HRESULT hr = D3D11CreateDevice( - /*adapter=*/nullptr, D3D_DRIVER_TYPE_HARDWARE, - /*software_rasterizer=*/nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, - /*feature_levels=*/nullptr, /*feature_levels_size=*/0, D3D11_SDK_VERSION, - &d3d11_device_, /*feature_level=*/nullptr, /*device_context=*/nullptr); - if (hr == DXGI_ERROR_UNSUPPORTED) { - // If a hardware device could not be created, use WARP which is a high speed - // software device. - hr = D3D11CreateDevice( - /*adapter=*/nullptr, D3D_DRIVER_TYPE_WARP, - /*software_rasterizer=*/nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, - /*feature_levels=*/nullptr, /*feature_levels_size=*/0, - D3D11_SDK_VERSION, &d3d11_device_, /*feature_level=*/nullptr, - /*device_context=*/nullptr); - } - - if (FAILED(hr)) { - RTC_LOG(LS_ERROR) << "Failed to create D3D11Device: " << hr; - } -} - -void WgcCapturerWin::CaptureFrame() { - RTC_DCHECK(callback_); - - if (!capture_source_) { - RTC_LOG(LS_ERROR) << "Source hasn't been selected"; - callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT, - /*frame=*/nullptr); - RecordWgcCapturerResult(WgcCapturerResult::kNoSourceSelected); - return; - } - - if (!d3d11_device_) { - RTC_LOG(LS_ERROR) << "No D3D11D3evice, cannot capture."; - callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT, - /*frame=*/nullptr); - RecordWgcCapturerResult(WgcCapturerResult::kNoDirect3dDevice); - return; - } - - int64_t capture_start_time_nanos = rtc::TimeNanos(); - - HRESULT hr; - WgcCaptureSession* capture_session = nullptr; - std::map::iterator session_iter = - ongoing_captures_.find(capture_source_->GetSourceId()); - if (session_iter == ongoing_captures_.end()) { - ComPtr item; - hr = capture_source_->GetCaptureItem(&item); - if (FAILED(hr)) { - RTC_LOG(LS_ERROR) << "Failed to create a GraphicsCaptureItem: " << hr; - callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT, - /*frame=*/nullptr); - RecordWgcCapturerResult(WgcCapturerResult::kItemCreationFailure); - return; - } - - std::pair::iterator, bool> - iter_success_pair = ongoing_captures_.emplace( - std::piecewise_construct, - std::forward_as_tuple(capture_source_->GetSourceId()), - std::forward_as_tuple(d3d11_device_, item)); - RTC_DCHECK(iter_success_pair.second); - capture_session = &iter_success_pair.first->second; - } else { - capture_session = &session_iter->second; - } - - if (!capture_session->IsCaptureStarted()) { - hr = capture_session->StartCapture(); - if (FAILED(hr)) { - RTC_LOG(LS_ERROR) << "Failed to start capture: " << hr; - ongoing_captures_.erase(capture_source_->GetSourceId()); - callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT, - /*frame=*/nullptr); - RecordWgcCapturerResult(WgcCapturerResult::kSessionStartFailure); - return; - } - } - - std::unique_ptr frame; - hr = capture_session->GetFrame(&frame); - if (FAILED(hr)) { - RTC_LOG(LS_ERROR) << "GetFrame failed: " << hr; - ongoing_captures_.erase(capture_source_->GetSourceId()); - callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT, - /*frame=*/nullptr); - RecordWgcCapturerResult(WgcCapturerResult::kGetFrameFailure); - return; - } - - if (!frame) { - callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_TEMPORARY, - /*frame=*/nullptr); - RecordWgcCapturerResult(WgcCapturerResult::kFrameDropped); - return; - } - - int capture_time_ms = (rtc::TimeNanos() - capture_start_time_nanos) / - rtc::kNumNanosecsPerMillisec; - RTC_HISTOGRAM_COUNTS_1000("WebRTC.DesktopCapture.Win.WgcCapturerFrameTime", - capture_time_ms); - frame->set_capture_time_ms(capture_time_ms); - frame->set_capturer_id(DesktopCapturerId::kWgcCapturerWin); - frame->set_may_contain_cursor(true); - frame->set_top_left(capture_source_->GetTopLeft()); - RecordWgcCapturerResult(WgcCapturerResult::kSuccess); - callback_->OnCaptureResult(DesktopCapturer::Result::SUCCESS, - std::move(frame)); -} - -bool WgcCapturerWin::IsSourceBeingCaptured(DesktopCapturer::SourceId id) { - std::map::iterator - session_iter = ongoing_captures_.find(id); - if (session_iter == ongoing_captures_.end()) - return false; - - return session_iter->second.IsCaptureStarted(); -} - -} // namespace webrtc diff --git a/webrtc/wgc_capturer_win.h b/webrtc/wgc_capturer_win.h deleted file mode 100644 index c7e497b..0000000 --- a/webrtc/wgc_capturer_win.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURER_WIN_H_ -#define MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURER_WIN_H_ - -#include -#include - -#include -#include - -#include "modules/desktop_capture/desktop_capture_options.h" -#include "modules/desktop_capture/desktop_capturer.h" -#include "modules/desktop_capture/win/screen_capture_utils.h" -#include "modules/desktop_capture/win/wgc_capture_session.h" -#include "modules/desktop_capture/win/wgc_capture_source.h" -#include "modules/desktop_capture/win/window_capture_utils.h" - -namespace webrtc { - -// WgcCapturerWin is initialized with an implementation of this base class, -// which it uses to find capturable sources of a particular type. This way, -// WgcCapturerWin can remain source-agnostic. -class SourceEnumerator { - public: - virtual ~SourceEnumerator() = default; - - virtual bool FindAllSources(DesktopCapturer::SourceList* sources) = 0; -}; - -class WindowEnumerator final : public SourceEnumerator { - public: - explicit WindowEnumerator(bool enumerate_current_process_windows) - : enumerate_current_process_windows_(enumerate_current_process_windows) {} - - WindowEnumerator(const WindowEnumerator&) = delete; - WindowEnumerator& operator=(const WindowEnumerator&) = delete; - - ~WindowEnumerator() override = default; - - bool FindAllSources(DesktopCapturer::SourceList* sources) override { - // WGC fails to capture windows with the WS_EX_TOOLWINDOW style, so we - // provide it as a filter to ensure windows with the style are not returned. - return window_capture_helper_.EnumerateCapturableWindows( - sources, enumerate_current_process_windows_, WS_EX_TOOLWINDOW); - } - - private: - WindowCaptureHelperWin window_capture_helper_; - bool enumerate_current_process_windows_; -}; - -class ScreenEnumerator final : public SourceEnumerator { - public: - ScreenEnumerator() = default; - - ScreenEnumerator(const ScreenEnumerator&) = delete; - ScreenEnumerator& operator=(const ScreenEnumerator&) = delete; - - ~ScreenEnumerator() override = default; - - bool FindAllSources(DesktopCapturer::SourceList* sources) override { - return webrtc::GetScreenList(sources); - } -}; - -// A capturer that uses the Window.Graphics.Capture APIs. It is suitable for -// both window and screen capture (but only one type per instance). Consumers -// should not instantiate this class directly, instead they should use -// |CreateRawWindowCapturer()| or |CreateRawScreenCapturer()| to receive a -// capturer appropriate for the type of source they want to capture. -class WgcCapturerWin : public DesktopCapturer { - public: - WgcCapturerWin(std::unique_ptr source_factory, - std::unique_ptr source_enumerator); - - WgcCapturerWin(const WgcCapturerWin&) = delete; - WgcCapturerWin& operator=(const WgcCapturerWin&) = delete; - - ~WgcCapturerWin() override; - - static std::unique_ptr CreateRawWindowCapturer( - const DesktopCaptureOptions& options); - - static std::unique_ptr CreateRawScreenCapturer( - const DesktopCaptureOptions& options); - - // DesktopCapturer interface. - bool GetSourceList(SourceList* sources) override; - bool SelectSource(SourceId id) override; - bool FocusOnSelectedSource() override; - void Start(Callback* callback) override; - void CaptureFrame() override; - - // Used in WgcCapturerTests. - bool IsSourceBeingCaptured(SourceId id); - - private: - // Factory to create a WgcCaptureSource for us whenever SelectSource is - // called. Initialized at construction with a source-specific implementation. - std::unique_ptr source_factory_; - - // The source enumerator helps us find capturable sources of the appropriate - // type. Initialized at construction with a source-specific implementation. - std::unique_ptr source_enumerator_; - - // The WgcCaptureSource represents the source we are capturing. It tells us - // if the source is capturable and it creates the GraphicsCaptureItem for us. - std::unique_ptr capture_source_; - - // A map of all the sources we are capturing and the associated - // WgcCaptureSession. Frames for the current source (indicated via - // SelectSource) will be retrieved from the appropriate session when - // requested via CaptureFrame. - // This helps us efficiently capture multiple sources (e.g. when consumers - // are trying to display a list of available capture targets with thumbnails). - std::map ongoing_captures_; - - // The callback that we deliver frames to, synchronously, before CaptureFrame - // returns. - Callback* callback_ = nullptr; - - // A Direct3D11 device that is shared amongst the WgcCaptureSessions, who - // require one to perform the capture. - Microsoft::WRL::ComPtr<::ID3D11Device> d3d11_device_; -}; - -} // namespace webrtc - -#endif // MODULES_DESKTOP_CAPTURE_WIN_WGC_CAPTURER_WIN_H_ diff --git a/webrtc/wgc_capturer_win_unittest.cc b/webrtc/wgc_capturer_win_unittest.cc deleted file mode 100644 index 0f1dac0..0000000 --- a/webrtc/wgc_capturer_win_unittest.cc +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#include "modules/desktop_capture/win/wgc_capturer_win.h" -#include -#include -#include -#include "modules/desktop_capture/desktop_capture_options.h" -#include "modules/desktop_capture/desktop_capture_types.h" -#include "modules/desktop_capture/desktop_capturer.h" -#include "modules/desktop_capture/win/test_support/test_window.h" -#include "modules/desktop_capture/win/window_capture_utils.h" -#include "rtc_base/checks.h" -#include "rtc_base/logging.h" -#include "rtc_base/thread.h" -#include "rtc_base/time_utils.h" -#include "rtc_base/win/scoped_com_initializer.h" -#include "rtc_base/win/windows_version.h" -#include "system_wrappers/include/metrics.h" -#include "test/gtest.h" -namespace webrtc { -namespace { -const char kWindowThreadName[] = "wgc_capturer_test_window_thread"; -const WCHAR kWindowTitle[] = L"WGC Capturer Test Window"; -const char kCapturerImplHistogram[] = - "WebRTC.DesktopCapture.Win.DesktopCapturerImpl"; -const char kCapturerResultHistogram[] = - "WebRTC.DesktopCapture.Win.WgcCapturerResult"; -const int kSuccess = 0; -const int kSessionStartFailure = 4; -const char kCaptureSessionResultHistogram[] = - "WebRTC.DesktopCapture.Win.WgcCaptureSessionStartResult"; -const int kSourceClosed = 1; -const char kCaptureTimeHistogram[] = - "WebRTC.DesktopCapture.Win.WgcCapturerFrameTime"; -const int kSmallWindowWidth = 200; -const int kSmallWindowHeight = 100; -const int kMediumWindowWidth = 300; -const int kMediumWindowHeight = 200; -const int kLargeWindowWidth = 400; -const int kLargeWindowHeight = 500; -// The size of the image we capture is slightly smaller than the actual size of -// the window. -const int kWindowWidthSubtrahend = 14; -const int kWindowHeightSubtrahend = 7; -// Custom message constants so we can direct our thread to close windows -// and quit running. -const UINT kNoOp = WM_APP; -const UINT kDestroyWindow = WM_APP + 1; -const UINT kQuitRunning = WM_APP + 2; -enum CaptureType { kWindowCapture = 0, kScreenCapture = 1 }; -} // namespace -class WgcCapturerWinTest : public ::testing::TestWithParam, - public DesktopCapturer::Callback { - public: - void SetUp() override { - if (rtc::rtc_win::GetVersion() < rtc::rtc_win::Version::VERSION_WIN10_RS5) { - RTC_LOG(LS_INFO) - << "Skipping WgcCapturerWinTests on Windows versions < RS5."; - GTEST_SKIP(); - } - com_initializer_ = - std::make_unique(ScopedCOMInitializer::kMTA); - EXPECT_TRUE(com_initializer_->Succeeded()); - } - void SetUpForWindowCapture(int window_width = kMediumWindowWidth, - int window_height = kMediumWindowHeight) { - capturer_ = WgcCapturerWin::CreateRawWindowCapturer( - DesktopCaptureOptions::CreateDefault()); - CreateWindowOnSeparateThread(window_width, window_height); - StartWindowThreadMessageLoop(); - source_id_ = GetTestWindowIdFromSourceList(); - } - void SetUpForScreenCapture() { - capturer_ = WgcCapturerWin::CreateRawScreenCapturer( - DesktopCaptureOptions::CreateDefault()); - source_id_ = GetScreenIdFromSourceList(); - } - void TearDown() override { - if (window_open_) { - CloseTestWindow(); - } - } - // The window must live on a separate thread so that we can run a message pump - // without blocking the test thread. This is necessary if we are interested in - // having GraphicsCaptureItem events (i.e. the Closed event) fire, and it more - // closely resembles how capture works in the wild. - void CreateWindowOnSeparateThread(int window_width, int window_height) { - window_thread_ = rtc::Thread::Create(); - window_thread_->SetName(kWindowThreadName, nullptr); - window_thread_->Start(); - window_thread_->Invoke(RTC_FROM_HERE, [this, window_width, - window_height]() { - window_thread_id_ = GetCurrentThreadId(); - window_info_ = - CreateTestWindow(kWindowTitle, window_height, window_width); - window_open_ = true; - while (!IsWindowResponding(window_info_.hwnd)) { - RTC_LOG(LS_INFO) << "Waiting for test window to become responsive in " - "WgcWindowCaptureTest."; - } - while (!IsWindowValidAndVisible(window_info_.hwnd)) { - RTC_LOG(LS_INFO) << "Waiting for test window to be visible in " - "WgcWindowCaptureTest."; - } - }); - ASSERT_TRUE(window_thread_->RunningForTest()); - ASSERT_FALSE(window_thread_->IsCurrent()); - } - void StartWindowThreadMessageLoop() { - window_thread_->PostTask(RTC_FROM_HERE, [this]() { - MSG msg; - BOOL gm; - while ((gm = ::GetMessage(&msg, NULL, 0, 0)) != 0 && gm != -1) { - ::DispatchMessage(&msg); - if (msg.message == kDestroyWindow) { - DestroyTestWindow(window_info_); - } - if (msg.message == kQuitRunning) { - PostQuitMessage(0); - } - } - }); - } - void CloseTestWindow() { - ::PostThreadMessage(window_thread_id_, kDestroyWindow, 0, 0); - ::PostThreadMessage(window_thread_id_, kQuitRunning, 0, 0); - window_thread_->Stop(); - window_open_ = false; - } - DesktopCapturer::SourceId GetTestWindowIdFromSourceList() { - // Frequently, the test window will not show up in GetSourceList because it - // was created too recently. Since we are confident the window will be found - // eventually we loop here until we find it. - intptr_t src_id; - do { - DesktopCapturer::SourceList sources; - EXPECT_TRUE(capturer_->GetSourceList(&sources)); - auto it = std::find_if( - sources.begin(), sources.end(), - [&](const DesktopCapturer::Source& src) { - return src.id == reinterpret_cast(window_info_.hwnd); - }); - src_id = it->id; - } while (src_id != reinterpret_cast(window_info_.hwnd)); - return src_id; - } - DesktopCapturer::SourceId GetScreenIdFromSourceList() { - DesktopCapturer::SourceList sources; - EXPECT_TRUE(capturer_->GetSourceList(&sources)); - EXPECT_GT(sources.size(), 0ULL); - return sources[0].id; - } - void DoCapture() { - // Sometimes the first few frames are empty becaues the capture engine is - // still starting up. We also may drop a few frames when the window is - // resized or un-minimized. - do { - capturer_->CaptureFrame(); - } while (result_ == DesktopCapturer::Result::ERROR_TEMPORARY); - EXPECT_EQ(result_, DesktopCapturer::Result::SUCCESS); - EXPECT_TRUE(frame_); - EXPECT_GT(metrics::NumEvents(kCapturerResultHistogram, kSuccess), - successful_captures_); - ++successful_captures_; - } - void ValidateFrame(int expected_width, int expected_height) { - EXPECT_EQ(frame_->size().width(), expected_width - kWindowWidthSubtrahend); - EXPECT_EQ(frame_->size().height(), - expected_height - kWindowHeightSubtrahend); - // Verify the buffer contains as much data as it should, and that the right - // colors are found. - int data_length = frame_->stride() * frame_->size().height(); - // The first and last pixel should have the same color because they will be - // from the border of the window. - // Pixels have 4 bytes of data so the whole pixel needs a uint32_t to fit. - uint32_t first_pixel = static_cast(*frame_->data()); - uint32_t last_pixel = static_cast( - *(frame_->data() + data_length - DesktopFrame::kBytesPerPixel)); - EXPECT_EQ(first_pixel, last_pixel); - // Let's also check a pixel from the middle of the content area, which the - // TestWindow will paint a consistent color for us to verify. - uint8_t* middle_pixel = frame_->data() + (data_length / 2); - int sub_pixel_offset = DesktopFrame::kBytesPerPixel / 4; - EXPECT_EQ(*middle_pixel, kTestWindowBValue); - middle_pixel += sub_pixel_offset; - EXPECT_EQ(*middle_pixel, kTestWindowGValue); - middle_pixel += sub_pixel_offset; - EXPECT_EQ(*middle_pixel, kTestWindowRValue); - middle_pixel += sub_pixel_offset; - // The window is opaque so we expect 0xFF for the Alpha channel. - EXPECT_EQ(*middle_pixel, 0xFF); - } - // DesktopCapturer::Callback interface - // The capturer synchronously invokes this method before |CaptureFrame()| - // returns. - void OnCaptureResult(DesktopCapturer::Result result, - std::unique_ptr frame) override { - result_ = result; - frame_ = std::move(frame); - } - protected: - std::unique_ptr com_initializer_; - DWORD window_thread_id_; - std::unique_ptr window_thread_; - WindowInfo window_info_; - intptr_t source_id_; - bool window_open_ = false; - DesktopCapturer::Result result_; - int successful_captures_ = 0; - std::unique_ptr frame_; - std::unique_ptr capturer_; -}; -TEST_P(WgcCapturerWinTest, SelectValidSource) { - if (GetParam() == CaptureType::kWindowCapture) { - SetUpForWindowCapture(); - } else { - SetUpForScreenCapture(); - } - EXPECT_TRUE(capturer_->SelectSource(source_id_)); -} -TEST_P(WgcCapturerWinTest, SelectInvalidSource) { - if (GetParam() == CaptureType::kWindowCapture) { - capturer_ = WgcCapturerWin::CreateRawWindowCapturer( - DesktopCaptureOptions::CreateDefault()); - source_id_ = kNullWindowId; - } else { - capturer_ = WgcCapturerWin::CreateRawScreenCapturer( - DesktopCaptureOptions::CreateDefault()); - source_id_ = kInvalidScreenId; - } - EXPECT_FALSE(capturer_->SelectSource(source_id_)); -} -TEST_P(WgcCapturerWinTest, Capture) { - if (GetParam() == CaptureType::kWindowCapture) { - SetUpForWindowCapture(); - } else { - SetUpForScreenCapture(); - } - EXPECT_TRUE(capturer_->SelectSource(source_id_)); - capturer_->Start(this); - EXPECT_GE(metrics::NumEvents(kCapturerImplHistogram, - DesktopCapturerId::kWgcCapturerWin), - 1); - DoCapture(); - EXPECT_GT(frame_->size().width(), 0); - EXPECT_GT(frame_->size().height(), 0); -} -TEST_P(WgcCapturerWinTest, CaptureTime) { - if (GetParam() == CaptureType::kWindowCapture) { - SetUpForWindowCapture(); - } else { - SetUpForScreenCapture(); - } - EXPECT_TRUE(capturer_->SelectSource(source_id_)); - capturer_->Start(this); - int64_t start_time; - do { - start_time = rtc::TimeNanos(); - capturer_->CaptureFrame(); - } while (result_ == DesktopCapturer::Result::ERROR_TEMPORARY); - int capture_time_ms = - (rtc::TimeNanos() - start_time) / rtc::kNumNanosecsPerMillisec; - EXPECT_TRUE(frame_); - // The test may measure the time slightly differently than the capturer. So we - // just check if it's within 5 ms. - EXPECT_NEAR(frame_->capture_time_ms(), capture_time_ms, 5); - EXPECT_GE( - metrics::NumEvents(kCaptureTimeHistogram, frame_->capture_time_ms()), 1); -} -INSTANTIATE_TEST_SUITE_P(SourceAgnostic, - WgcCapturerWinTest, - ::testing::Values(CaptureType::kWindowCapture, - CaptureType::kScreenCapture)); -// Monitor specific tests. -TEST_F(WgcCapturerWinTest, FocusOnMonitor) { - SetUpForScreenCapture(); - EXPECT_TRUE(capturer_->SelectSource(0)); - // You can't set focus on a monitor. - EXPECT_FALSE(capturer_->FocusOnSelectedSource()); -} -TEST_F(WgcCapturerWinTest, CaptureAllMonitors) { - SetUpForScreenCapture(); - EXPECT_TRUE(capturer_->SelectSource(kFullDesktopScreenId)); - capturer_->Start(this); - DoCapture(); - EXPECT_GT(frame_->size().width(), 0); - EXPECT_GT(frame_->size().height(), 0); -} -// Window specific tests. -TEST_F(WgcCapturerWinTest, FocusOnWindow) { - capturer_ = WgcCapturerWin::CreateRawWindowCapturer( - DesktopCaptureOptions::CreateDefault()); - window_info_ = CreateTestWindow(kWindowTitle); - source_id_ = GetScreenIdFromSourceList(); - EXPECT_TRUE(capturer_->SelectSource(source_id_)); - EXPECT_TRUE(capturer_->FocusOnSelectedSource()); - HWND hwnd = reinterpret_cast(source_id_); - EXPECT_EQ(hwnd, ::GetActiveWindow()); - EXPECT_EQ(hwnd, ::GetForegroundWindow()); - EXPECT_EQ(hwnd, ::GetFocus()); - DestroyTestWindow(window_info_); -} -TEST_F(WgcCapturerWinTest, SelectMinimizedWindow) { - SetUpForWindowCapture(); - MinimizeTestWindow(reinterpret_cast(source_id_)); - EXPECT_FALSE(capturer_->SelectSource(source_id_)); - UnminimizeTestWindow(reinterpret_cast(source_id_)); - EXPECT_TRUE(capturer_->SelectSource(source_id_)); -} -TEST_F(WgcCapturerWinTest, SelectClosedWindow) { - SetUpForWindowCapture(); - EXPECT_TRUE(capturer_->SelectSource(source_id_)); - CloseTestWindow(); - EXPECT_FALSE(capturer_->SelectSource(source_id_)); -} -TEST_F(WgcCapturerWinTest, UnsupportedWindowStyle) { - // Create a window with the WS_EX_TOOLWINDOW style, which WGC does not - // support. - window_info_ = CreateTestWindow(kWindowTitle, kMediumWindowWidth, - kMediumWindowHeight, WS_EX_TOOLWINDOW); - capturer_ = WgcCapturerWin::CreateRawWindowCapturer( - DesktopCaptureOptions::CreateDefault()); - DesktopCapturer::SourceList sources; - EXPECT_TRUE(capturer_->GetSourceList(&sources)); - auto it = std::find_if( - sources.begin(), sources.end(), [&](const DesktopCapturer::Source& src) { - return src.id == reinterpret_cast(window_info_.hwnd); - }); - // We should not find the window, since we filter for unsupported styles. - EXPECT_EQ(it, sources.end()); - DestroyTestWindow(window_info_); -} -TEST_F(WgcCapturerWinTest, IncreaseWindowSizeMidCapture) { - SetUpForWindowCapture(kSmallWindowWidth, kSmallWindowHeight); - EXPECT_TRUE(capturer_->SelectSource(source_id_)); - capturer_->Start(this); - DoCapture(); - ValidateFrame(kSmallWindowWidth, kSmallWindowHeight); - ResizeTestWindow(window_info_.hwnd, kSmallWindowWidth, kMediumWindowHeight); - DoCapture(); - // We don't expect to see the new size until the next capture, as the frame - // pool hadn't had a chance to resize yet to fit the new, larger image. - DoCapture(); - ValidateFrame(kSmallWindowWidth, kMediumWindowHeight); - ResizeTestWindow(window_info_.hwnd, kLargeWindowWidth, kMediumWindowHeight); - DoCapture(); - DoCapture(); - ValidateFrame(kLargeWindowWidth, kMediumWindowHeight); -} -TEST_F(WgcCapturerWinTest, ReduceWindowSizeMidCapture) { - SetUpForWindowCapture(kLargeWindowWidth, kLargeWindowHeight); - EXPECT_TRUE(capturer_->SelectSource(source_id_)); - capturer_->Start(this); - DoCapture(); - ValidateFrame(kLargeWindowWidth, kLargeWindowHeight); - ResizeTestWindow(window_info_.hwnd, kLargeWindowWidth, kMediumWindowHeight); - // We expect to see the new size immediately because the image data has shrunk - // and will fit in the existing buffer. - DoCapture(); - ValidateFrame(kLargeWindowWidth, kMediumWindowHeight); - ResizeTestWindow(window_info_.hwnd, kSmallWindowWidth, kMediumWindowHeight); - DoCapture(); - ValidateFrame(kSmallWindowWidth, kMediumWindowHeight); -} -TEST_F(WgcCapturerWinTest, MinimizeWindowMidCapture) { - SetUpForWindowCapture(); - EXPECT_TRUE(capturer_->SelectSource(source_id_)); - capturer_->Start(this); - // Minmize the window and capture should continue but return temporary errors. - MinimizeTestWindow(window_info_.hwnd); - for (int i = 0; i < 10; ++i) { - capturer_->CaptureFrame(); - EXPECT_EQ(result_, DesktopCapturer::Result::ERROR_TEMPORARY); - } - // Reopen the window and the capture should continue normally. - UnminimizeTestWindow(window_info_.hwnd); - DoCapture(); - // We can't verify the window size here because the test window does not - // repaint itself after it is unminimized, but capturing successfully is still - // a good test. -} -TEST_F(WgcCapturerWinTest, CloseWindowMidCapture) { - SetUpForWindowCapture(); - EXPECT_TRUE(capturer_->SelectSource(source_id_)); - capturer_->Start(this); - DoCapture(); - ValidateFrame(kMediumWindowWidth, kMediumWindowHeight); - CloseTestWindow(); - // We need to call GetMessage to trigger the Closed event and the capturer's - // event handler for it. If we are too early and the Closed event hasn't - // arrived yet we should keep trying until the capturer receives it and stops. - auto* wgc_capturer = static_cast(capturer_.get()); - while (wgc_capturer->IsSourceBeingCaptured(source_id_)) { - // Since the capturer handles the Closed message, there will be no message - // for us and GetMessage will hang, unless we send ourselves a message - // first. - ::PostThreadMessage(GetCurrentThreadId(), kNoOp, 0, 0); - MSG msg; - ::GetMessage(&msg, NULL, 0, 0); - ::DispatchMessage(&msg); - } - // Occasionally, one last frame will have made it into the frame pool before - // the window closed. The first call will consume it, and in that case we need - // to make one more call to CaptureFrame. - capturer_->CaptureFrame(); - if (result_ == DesktopCapturer::Result::SUCCESS) - capturer_->CaptureFrame(); - EXPECT_GE(metrics::NumEvents(kCapturerResultHistogram, kSessionStartFailure), - 1); - EXPECT_GE(metrics::NumEvents(kCaptureSessionResultHistogram, kSourceClosed), - 1); - EXPECT_EQ(result_, DesktopCapturer::Result::ERROR_PERMANENT); -} -} // namespace webrtc diff --git a/webrtc/wgc_desktop_frame.cc b/webrtc/wgc_desktop_frame.cc deleted file mode 100644 index 9e37fc6..0000000 --- a/webrtc/wgc_desktop_frame.cc +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#include "modules/desktop_capture/win/wgc_desktop_frame.h" -#include -namespace webrtc { -WgcDesktopFrame::WgcDesktopFrame(DesktopSize size, - int stride, - std::vector&& image_data) - : DesktopFrame(size, stride, image_data.data(), nullptr), - image_data_(std::move(image_data)) {} -WgcDesktopFrame::~WgcDesktopFrame() = default; -} // namespace webrtc diff --git a/webrtc/wgc_desktop_frame.h b/webrtc/wgc_desktop_frame.h deleted file mode 100644 index e64fb69..0000000 --- a/webrtc/wgc_desktop_frame.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -#ifndef MODULES_DESKTOP_CAPTURE_WIN_WGC_DESKTOP_FRAME_H_ -#define MODULES_DESKTOP_CAPTURE_WIN_WGC_DESKTOP_FRAME_H_ -#include -#include -#include -#include -#include "desktop_frame.h" -#include "desktop_geometry.h" -namespace webrtc { -// DesktopFrame implementation used by capturers that use the -// Windows.Graphics.Capture API. -class WgcDesktopFrame final : public DesktopFrame { - public: - // WgcDesktopFrame receives an rvalue reference to the |image_data| vector - // so that it can take ownership of it (and avoid a copy). - WgcDesktopFrame(DesktopSize size, - int stride, - std::vector&& image_data); - WgcDesktopFrame(const WgcDesktopFrame&) = delete; - WgcDesktopFrame& operator=(const WgcDesktopFrame&) = delete; - ~WgcDesktopFrame() override; - private: - std::vector image_data_; -}; -} // namespace webrtc -#endif // MODULES_DESKTOP_CAPTURE_WIN_WGC_DESKTOP_FRAME_H_ diff --git a/xmake.lua b/xmake.lua index b2d4175..713200b 100644 --- a/xmake.lua +++ b/xmake.lua @@ -29,16 +29,30 @@ target("log") add_headerfiles("../../src/log/log.h") add_includedirs("../../src/log", {public = true}) -target("remote_desk") - set_kind("binary") - add_deps("projectx") +target("screen_capture") + set_kind("static") add_packages("log") - add_packages("ffmpeg") - add_packages("vcpkg::sdl2") - add_links("avfilter", "avdevice", "avformat", "avcodec", "swscale", "swresample", "avutil") - add_files("dll/*.cpp") + add_files("screen_capture/*.cpp") + add_includedirs("screen_capture", {public = true}) + +target("remote_desk_server") + set_kind("binary") + add_packages("log", "ffmpeg") + add_deps("projectx", "screen_capture") + add_files("remote_desk_server/*.cpp") add_includedirs("../../src/interface") - add_links("SDL2-static", "SDL2main", "Shell32", "gdi32", "winmm", - "setupapi", "version", "WindowsApp", "Imm32", "avutil") + -- add_links("avformat", "swscale") + +-- target("remote_desk") +-- set_kind("binary") +-- add_deps("projectx") +-- add_packages("log") +-- add_packages("ffmpeg") +-- add_packages("vcpkg::sdl2") +-- add_links("avfilter", "avdevice", "avformat", "avcodec", "swscale", "swresample", "avutil") +-- add_files("**.cpp") +-- add_includedirs("../../src/interface") +-- add_links("SDL2-static", "SDL2main", "Shell32", "gdi32", "winmm", +-- "setupapi", "version", "WindowsApp", "Imm32", "avutil")