From ae67ad961e57c7b36b9c9197f617aef9e9b38fb6 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Tue, 29 Aug 2023 17:33:58 +0800 Subject: [PATCH] Use sdl2 to display capture screen --- demo/SimpleCapture.cpp | 12 +- dll/error_define.h | 218 ---------------------------- dll/export.cpp | 17 --- dll/export.h | 50 ------- dll/head.h | 21 --- dll/main.cpp | 142 ++++++++++++++++--- dll/pch.cpp | 1 - dll/pch.h | 48 ------- dll/record_desktop.cpp | 23 --- dll/record_desktop.h | 124 ---------------- dll/record_desktop_wgc.cpp | 139 ------------------ dll/record_desktop_wgc.h | 65 --------- dll/screen_capture_wgc.cpp | 202 ++++++++++++++++++++++++++ dll/screen_capture_wgc.h | 76 ++++++++++ dll/wgc_session.h | 40 ++++++ dll/wgc_session_impl.cpp | 281 +++++++++++++++---------------------- dll/wgc_session_impl.h | 104 ++++++++------ xmake.lua | 10 +- 18 files changed, 624 insertions(+), 949 deletions(-) delete mode 100644 dll/error_define.h delete mode 100644 dll/export.cpp delete mode 100644 dll/export.h delete mode 100644 dll/head.h delete mode 100644 dll/pch.cpp delete mode 100644 dll/pch.h delete mode 100644 dll/record_desktop.cpp delete mode 100644 dll/record_desktop.h delete mode 100644 dll/record_desktop_wgc.cpp delete mode 100644 dll/record_desktop_wgc.h create mode 100644 dll/screen_capture_wgc.cpp create mode 100644 dll/screen_capture_wgc.h create mode 100644 dll/wgc_session.h diff --git a/demo/SimpleCapture.cpp b/demo/SimpleCapture.cpp index d927d5f..ec72bb2 100644 --- a/demo/SimpleCapture.cpp +++ b/demo/SimpleCapture.cpp @@ -12,9 +12,10 @@ // //********************************************************* -#include "pch.h" #include "SimpleCapture.h" +#include "pch.h" + using namespace winrt; using namespace Windows; using namespace Windows::Foundation; @@ -107,7 +108,6 @@ void SimpleCapture::OnFrameArrived( auto frameSurface = GetDXGIInterfaceFromObject(frame.Surface()); - com_ptr backBuffer; check_hresult(m_swapChain->GetBuffer(0, guid_of(), backBuffer.put_void())); @@ -123,8 +123,7 @@ void SimpleCapture::OnFrameArrived( auto frameSurface = GetDXGIInterfaceFromObject(frame.Surface()); - if (!m_mappedTexture || newSize) - CreateMappedTexture(frameSurface); + if (!m_mappedTexture || newSize) CreateMappedTexture(frameSurface); m_d3dContext->CopyResource(m_mappedTexture.get(), frameSurface.get()); @@ -136,8 +135,7 @@ void SimpleCapture::OnFrameArrived( #if 1 if (mapInfo.pData) { static unsigned char *buffer = nullptr; - if (buffer && newSize) - delete[] buffer; + if (buffer && newSize) delete[] buffer; if (!buffer) buffer = new unsigned char[frameContentSize.Width * @@ -156,7 +154,7 @@ void SimpleCapture::OnFrameArrived( bi.biWidth = frameContentSize.Width; bi.biHeight = frameContentSize.Height * (-1); bi.biPlanes = 1; - bi.biBitCount = 32; // should get from system color bits + bi.biBitCount = 32; // should get from system color bits bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; diff --git a/dll/error_define.h b/dll/error_define.h deleted file mode 100644 index a8cfc1e..0000000 --- a/dll/error_define.h +++ /dev/null @@ -1,218 +0,0 @@ -#ifndef ERROR_DEFINE -#define ERROR_DEFINE - - -enum AM_ERROR{ - AE_NO = 0, - AE_ERROR, - AE_UNSUPPORT, - AE_INVALID_CONTEXT, - AE_NEED_INIT, - AE_TIMEOUT, - AE_ALLOCATE_FAILED, - - //AE_CO_ - AE_CO_INITED_FAILED, - AE_CO_CREATE_FAILED, - AE_CO_GETENDPOINT_FAILED, - AE_CO_ACTIVE_DEVICE_FAILED, - AE_CO_GET_FORMAT_FAILED, - AE_CO_AUDIOCLIENT_INIT_FAILED, - AE_CO_GET_CAPTURE_FAILED, - AE_CO_CREATE_EVENT_FAILED, - AE_CO_SET_EVENT_FAILED, - AE_CO_START_FAILED, - AE_CO_ENUMENDPOINT_FAILED, - AE_CO_GET_ENDPOINT_COUNT_FAILED, - AE_CO_GET_ENDPOINT_ID_FAILED, - AE_CO_OPEN_PROPERTY_FAILED, - AE_CO_GET_VALUE_FAILED, - AE_CO_GET_BUFFER_FAILED, - AE_CO_RELEASE_BUFFER_FAILED, - AE_CO_GET_PACKET_FAILED, - AE_CO_PADDING_UNEXPECTED, - - //AE_FFMPEG_ - AE_FFMPEG_OPEN_INPUT_FAILED, - AE_FFMPEG_FIND_STREAM_FAILED, - AE_FFMPEG_FIND_DECODER_FAILED, - AE_FFMPEG_OPEN_CODEC_FAILED, - AE_FFMPEG_READ_FRAME_FAILED, - AE_FFMPEG_READ_PACKET_FAILED, - AE_FFMPEG_DECODE_FRAME_FAILED, - AE_FFMPEG_NEW_SWSCALE_FAILED, - AE_FFMPEG_FIND_ENCODER_FAILED, - AE_FFMPEG_ALLOC_CONTEXT_FAILED, - AE_FFMPEG_ENCODE_FRAME_FAILED, - AE_FFMPEG_ALLOC_FRAME_FAILED, - AE_FFMPEG_OPEN_IO_FAILED, - AE_FFMPEG_CREATE_STREAM_FAILED, - AE_FFMPEG_COPY_PARAMS_FAILED, - AE_RESAMPLE_INIT_FAILED, - AE_FFMPEG_NEW_STREAM_FAILED, - AE_FFMPEG_FIND_INPUT_FMT_FAILED, - AE_FFMPEG_WRITE_HEADER_FAILED, - AE_FFMPEG_WRITE_TRAILER_FAILED, - AE_FFMPEG_WRITE_FRAME_FAILED, - - //AE_FILTER_ - AE_FILTER_ALLOC_GRAPH_FAILED, - AE_FILTER_CREATE_FILTER_FAILED, - AE_FILTER_PARSE_PTR_FAILED, - AE_FILTER_CONFIG_FAILED, - AE_FILTER_INVALID_CTX_INDEX, - AE_FILTER_ADD_FRAME_FAILED, - - //AE_GDI_ - AE_GDI_GET_DC_FAILED, - AE_GDI_CREATE_DC_FAILED, - AE_GDI_CREATE_BMP_FAILED, - AE_GDI_BITBLT_FAILED, - AE_GDI_GET_DIBITS_FAILED, - - //AE_D3D_ - AE_D3D_LOAD_FAILED, - AE_D3D_GET_PROC_FAILED, - AE_D3D_CREATE_DEVICE_FAILED, - AE_D3D_QUERYINTERFACE_FAILED, - AE_D3D_CREATE_VERTEX_SHADER_FAILED, - AE_D3D_CREATE_INLAYOUT_FAILED, - AE_D3D_CREATE_PIXEL_SHADER_FAILED, - AE_D3D_CREATE_SAMPLERSTATE_FAILED, - - //AE_DXGI_ - AE_DXGI_GET_PROC_FAILED, - AE_DXGI_GET_ADAPTER_FAILED, - AE_DXGI_GET_FACTORY_FAILED, - AE_DXGI_FOUND_ADAPTER_FAILED, - - //AE_DUP_ - AE_DUP_ATTATCH_FAILED, - AE_DUP_QI_FAILED, - AE_DUP_GET_PARENT_FAILED, - AE_DUP_ENUM_OUTPUT_FAILED, - AE_DUP_DUPLICATE_MAX_FAILED, - AE_DUP_DUPLICATE_FAILED, - AE_DUP_RELEASE_FRAME_FAILED, - AE_DUP_ACQUIRE_FRAME_FAILED, - AE_DUP_QI_FRAME_FAILED, - AE_DUP_CREATE_TEXTURE_FAILED, - AE_DUP_QI_DXGI_FAILED, - AE_DUP_MAP_FAILED, - AE_DUP_GET_CURSORSHAPE_FAILED, - - //AE_REMUX_ - AE_REMUX_RUNNING, - AE_REMUX_NOT_EXIST, - AE_REMUX_INVALID_INOUT, - - // AE_WGC_ - AE_WGC_CREATE_CAPTURER_FAILED, - - AE_MAX -}; - -static const char *ERRORS_STR[] = { - "no error", //AE_NO - "error", //AE_ERROR - "not support for now", //AE_UNSUPPORT - "invalid context", //AE_INVALID_CONTEXT - "need init first", //AE_NEED_INIT - "operation timeout", //AE_TIMEOUT - "allocate memory failed", //AE_ALLOCATE_FAILED, - - "com init failed", //AE_CO_INITED_FAILED - "com create instance failed", //AE_CO_CREATE_FAILED - "com get endpoint failed", //AE_CO_GETENDPOINT_FAILED - "com active device failed", //AE_CO_ACTIVE_DEVICE_FAILED - "com get wave formatex failed", //AE_CO_GET_FORMAT_FAILED - "com audio client init failed", //AE_CO_AUDIOCLIENT_INIT_FAILED - "com audio get capture failed", //AE_CO_GET_CAPTURE_FAILED - "com audio create event failed", //AE_CO_CREATE_EVENT_FAILED - "com set ready event failed", //AE_CO_SET_EVENT_FAILED - "com start to record failed", //AE_CO_START_FAILED - "com enum audio endpoints failed", //AE_CO_ENUMENDPOINT_FAILED - "com get endpoints count failed", //AE_CO_GET_ENDPOINT_COUNT_FAILED - "com get endpoint id failed", //AE_CO_GET_ENDPOINT_ID_FAILED - "com open endpoint property failed", //AE_CO_OPEN_PROPERTY_FAILED - "com get property value failed", //AE_CO_GET_VALUE_FAILED - "com get buffer failed", //AE_CO_GET_BUFFER_FAILED - "com release buffer failed", //AE_CO_RELEASE_BUFFER_FAILED - "com get packet size failed", //AE_CO_GET_PACKET_FAILED - "com get padding size unexpected", //AE_CO_PADDING_UNEXPECTED - - "ffmpeg open input failed", //AE_FFMPEG_OPEN_INPUT_FAILED - "ffmpeg find stream info failed", //AE_FFMPEG_FIND_STREAM_FAILED - "ffmpeg find decoder failed", //AE_FFMPEG_FIND_DECODER_FAILED - "ffmpeg open codec failed", //AE_FFMPEG_OPEN_CODEC_FAILED - "ffmpeg read frame failed", //AE_FFMPEG_READ_FRAME_FAILED - "ffmpeg read packet failed", //AE_FFMPEG_READ_PACKET_FAILED - "ffmpeg decode frame failed", //AE_FFMPEG_DECODE_FRAME_FAILED - "ffmpeg create swscale failed", //AE_FFMPEG_NEW_SWSCALE_FAILED - - "ffmpeg find encoder failed", //AE_FFMPEG_FIND_ENCODER_FAILED - "ffmpeg alloc context failed", //AE_FFMPEG_ALLOC_CONTEXT_FAILED - "ffmpeg encode frame failed", //AE_FFMPEG_ENCODE_FRAME_FAILED - "ffmpeg alloc frame failed", //AE_FFMPEG_ALLOC_FRAME_FAILED - - "ffmpeg open io ctx failed", //AE_FFMPEG_OPEN_IO_FAILED - "ffmpeg new stream failed", //AE_FFMPEG_CREATE_STREAM_FAILED - "ffmpeg copy parameters failed", //AE_FFMPEG_COPY_PARAMS_FAILED - "resampler init failed", //AE_RESAMPLE_INIT_FAILED - "ffmpeg new out stream failed", //AE_FFMPEG_NEW_STREAM_FAILED - "ffmpeg find input format failed", //AE_FFMPEG_FIND_INPUT_FMT_FAILED - "ffmpeg write file header failed", //AE_FFMPEG_WRITE_HEADER_FAILED - "ffmpeg write file trailer failed", //AE_FFMPEG_WRITE_TRAILER_FAILED - "ffmpeg write frame failed", //AE_FFMPEG_WRITE_FRAME_FAILED - - "avfilter alloc avfilter failed", //AE_FILTER_ALLOC_GRAPH_FAILED - "avfilter create graph failed", //AE_FILTER_CREATE_FILTER_FAILED - "avfilter parse ptr failed", //AE_FILTER_PARSE_PTR_FAILED - "avfilter config graph failed", //AE_FILTER_CONFIG_FAILED - "avfilter invalid ctx index", //AE_FILTER_INVALID_CTX_INDEX - "avfilter add frame failed", //AE_FILTER_ADD_FRAME_FAILED - - "gdi get dc failed", //AE_GDI_GET_DC_FAILED - "gdi create dc failed", //AE_GDI_CREATE_DC_FAILED - "gdi create bmp failed", //AE_GDI_CREATE_BMP_FAILED - "gdi bitblt failed", //AE_GDI_BITBLT_FAILED - "gid geet dibbits failed", //AE_GDI_GET_DIBITS_FAILED - - "d3d11 library load failed", //AE_D3D_LOAD_FAILED - "d3d11 proc get failed", //AE_D3D_GET_PROC_FAILED - "d3d11 create device failed", //AE_D3D_CREATE_DEVICE_FAILED - "d3d11 query interface failed", //AE_D3D_QUERYINTERFACE_FAILED - "d3d11 create vertex shader failed",//AE_D3D_CREATE_VERTEX_SHADER_FAILED - "d3d11 create input layout failed", //AE_D3D_CREATE_INLAYOUT_FAILED - "d3d11 create pixel shader failed", //AE_D3D_CREATE_PIXEL_SHADER_FAILED - "d3d11 create sampler state failed",//AE_D3D_CREATE_SAMPLERSTATE_FAILED - - "dxgi get proc address failed", //AE_DXGI_GET_PROC_FAILED - "dxgi get adapter failed", //AE_DXGI_GET_ADAPTER_FAILED - "dxgi get factory failed", //AE_DXGI_GET_FACTORY_FAILED - "dxgi specified adapter not found", //AE_DXGI_FOUND_ADAPTER_FAILED - - "duplication attatch desktop failed", //AE_DUP_ATTATCH_FAILED - "duplication query interface failed", //AE_DUP_QI_FAILED - "duplication get parent failed", //AE_DUP_GET_PARENT_FAILED - "duplication enum ouput failed", //AE_DUP_ENUM_OUTPUT_FAILED - "duplication duplicate unavailable", //AE_DUP_DUPLICATE_MAX_FAILED - "duplication duplicate failed", //AE_DUP_DUPLICATE_FAILED - "duplication release frame failed", //AE_DUP_RELEASE_FRAME_FAILED - "duplication acquire frame failed", //AE_DUP_ACQUIRE_FRAME_FAILED - "duplication qi frame failed", //AE_DUP_QI_FRAME_FAILED - "duplication create texture failed", //AE_DUP_CREATE_TEXTURE_FAILED - "duplication dxgi qi failed", //AE_DUP_QI_DXGI_FAILED - "duplication map rects failed", //AE_DUP_MAP_FAILED - "duplication get cursor shape failed",//AE_DUP_GET_CURSORSHAPE_FAILED - - "remux is already running", //AE_REMUX_RUNNING - "remux input file do not exist", //AE_REMUX_NOT_EXIST - "remux input or output file invalid", //AE_REMUX_INVALID_INOUT -}; - -#define err2str(e) e < AE_MAX ? ERRORS_STR[e] : "unknown" - -#define AMERROR_CHECK(err) if(err != AE_NO) return err - -#endif // !ERROR_DEFINE \ No newline at end of file diff --git a/dll/export.cpp b/dll/export.cpp deleted file mode 100644 index 87ca8a7..0000000 --- a/dll/export.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "pch.h" - -#include - -bool wgc_is_supported() { - try { - /* no contract for IGraphicsCaptureItemInterop, verify 10.0.18362.0 */ - return winrt::Windows::Foundation::Metadata::ApiInformation:: - IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 8); - } catch (const winrt::hresult_error &) { - return false; - } catch (...) { - return false; - } -} - -am::wgc_session *wgc_create_session() { return new am::wgc_session_impl(); } \ No newline at end of file diff --git a/dll/export.h b/dll/export.h deleted file mode 100644 index 90873d1..0000000 --- a/dll/export.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include - -#ifdef AMRECORDER_IMPORT -#define AMRECORDER_API extern "C" __declspec(dllimport) -#else -#define AMRECORDER_API extern "C" __declspec(dllexport) -#endif - -namespace am { - -class wgc_session { -public: - struct wgc_session_frame { - unsigned int width; - unsigned int height; - unsigned int row_pitch; - - const unsigned char *data; - }; - - class wgc_session_observer { - public: - virtual ~wgc_session_observer() {} - virtual void on_frame(const wgc_session_frame &frame) = 0; - }; - -public: - virtual void release() = 0; - - virtual int initialize(HWND hwnd) = 0; - virtual int initialize(HMONITOR hmonitor) = 0; - - virtual void register_observer(wgc_session_observer *observer) = 0; - - virtual int start() = 0; - virtual int stop() = 0; - - virtual int pause() = 0; - virtual int resume() = 0; - -protected: - virtual ~wgc_session(){}; -}; - -} // namespace am - -AMRECORDER_API bool wgc_is_supported(); -AMRECORDER_API am::wgc_session *wgc_create_session(); \ No newline at end of file diff --git a/dll/head.h b/dll/head.h deleted file mode 100644 index 32e7836..0000000 --- a/dll/head.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _HEAD_H_ -#define _HEAD_H_ - -#include "record_desktop.h" - -class rd : public am::record_desktop { - public: - rd(){}; - virtual ~rd(){}; - - int init(const RECORD_DESKTOP_RECT &rect, const int fps) { return 0; }; - - int start() { return 0; }; - int pause() { return 0; }; - int resume() { return 0; }; - int stop() { return 0; }; - - void clean_up() {} -}; - -#endif \ No newline at end of file diff --git a/dll/main.cpp b/dll/main.cpp index ab1f1bf..9a016a3 100644 --- a/dll/main.cpp +++ b/dll/main.cpp @@ -1,19 +1,91 @@ -#define AMRECORDER_IMPORT + +#include + +#include #include +#include -#include "export.h" -#include "head.h" -#include "record_desktop_wgc.h" +#include "screen_capture_wgc.h" + +extern "C" { +#include +#include +}; + +#define SDL_MAIN_HANDLED +#include "SDL2/SDL.h" + +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; + +// Refresh Event +#define REFRESH_EVENT (SDL_USEREVENT + 1) + +int thread_exit = 0; + +int refresh_video(void *opaque) { + while (thread_exit == 0) { + SDL_Event event; + event.type = REFRESH_EVENT; + SDL_PushEvent(&event); + SDL_Delay(10); + } + return 0; +} + +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_YUV420P, 1280, 720, 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_YUV420P, width, height, 1); + av_image_fill_arrays(Output_pFrame->data, Output_pFrame->linesize, des_buffer, + AV_PIX_FMT_NV12, 1280, 720, 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 OnFrame(unsigned char *data, int size, int width, int height) { + std::cout << "Receive frame: w:" << width << " h:" << height + << " size:" << size << std::endl; + // YUV420ToNV12FFmpeg(data, width, height, dst_buffer); + + // SDL_UpdateTexture(sdlTexture, NULL, data, pixel_w); + memcpy(rgbData, data, width * height); + + // 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); +} int main() { - // bool is_supported = wgc_is_supported(); - // if (!wgc_is_supported) { - // std::cout << "Not support wgc" << std::endl; - // return -1; - // } - - static am::record_desktop *recorder = new am::record_desktop_wgc(); + ScreenCaptureWgc *recorder = new ScreenCaptureWgc(); RECORD_DESKTOP_RECT rect; rect.left = 0; @@ -21,15 +93,51 @@ int main() { rect.right = GetSystemMetrics(SM_CXSCREEN); rect.bottom = GetSystemMetrics(SM_CYSCREEN); - recorder->init(rect, 10); + recorder->Init(rect, 10, OnFrame); - recorder->start(); - // int pause() override; - // int resume() override; - // int stop() override; + recorder->Start(); + if (SDL_Init(SDL_INIT_VIDEO)) { + printf("Could not initialize SDL - %s\n", SDL_GetError()); + return -1; + } + + 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 create window - exiting:%s\n", SDL_GetError()); + return -1; + } + sdlRenderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED); + + Uint32 pixformat = 0; + pixformat = SDL_PIXELFORMAT_NV12; + + // sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, + // SDL_TEXTUREACCESS_STREAMING, pixel_w, + // pixel_h); + + SDL_Surface *surface = + SDL_CreateRGBSurfaceFrom(rgbData, pixel_w, pixel_h, 24, pixel_w * 3, + 0x000000FF, 0x0000FF00, 0x00FF0000, 0); + + sdlTexture = SDL_CreateTextureFromSurface(sdlRenderer, surface); + + SDL_Thread *refresh_thread = SDL_CreateThread(refresh_video, NULL, NULL); + SDL_Event event; while (1) { + // Wait + SDL_WaitEvent(&event); + if (event.type == REFRESH_EVENT) { + } else if (event.type == SDL_WINDOWEVENT) { + // If Resize + SDL_GetWindowSize(screen, &screen_w, &screen_h); + } else if (event.type == SDL_QUIT) { + break; + } } return 0; -} \ No newline at end of file +} diff --git a/dll/pch.cpp b/dll/pch.cpp deleted file mode 100644 index 1730571..0000000 --- a/dll/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" \ No newline at end of file diff --git a/dll/pch.h b/dll/pch.h deleted file mode 100644 index aa4c0ab..0000000 --- a/dll/pch.h +++ /dev/null @@ -1,48 +0,0 @@ -// pch.h: This is a precompiled header file. -// Files listed below are compiled only once, improving build performance for -// future builds. This also affects IntelliSense performance, including code -// completion and many code browsing features. However, files listed here are -// ALL re-compiled if any one of them is updated between builds. Do not add -// files here that you will be updating frequently as this negates the -// performance advantage. - -#ifndef PCH_H -#define PCH_H - -// add headers that you want to pre-compile here -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -// Windows Header Files - -#include -#include - -// WinRT -#include -#include -#include -#include -#include -#include - -#include - - -// STL -#include -#include - -// D3D -#include -#include -#include -#include - -// windowws - -#include - -#include "error_define.h" -#include "export.h" -#include "wgc_session_impl.h" - -#endif // PCH_H diff --git a/dll/record_desktop.cpp b/dll/record_desktop.cpp deleted file mode 100644 index 8bf0927..0000000 --- a/dll/record_desktop.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "record_desktop.h" - -am::record_desktop::record_desktop() -{ - _running = false; - _paused = false; - _inited = false; - - _on_data = nullptr; - _on_error = nullptr; - - _device_name = ""; - _data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_BGRA; - - _time_base = { 1,AV_TIME_BASE }; - _start_time = 0; - _pixel_fmt = AV_PIX_FMT_NONE; -} - -am::record_desktop::~record_desktop() -{ - -} diff --git a/dll/record_desktop.h b/dll/record_desktop.h deleted file mode 100644 index 0780538..0000000 --- a/dll/record_desktop.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef RECORD_DESKTOP -#define RECORD_DESKTOP - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -} - -#include -#include -#include -#include - -typedef enum { - DT_DESKTOP_NO = 0, - DT_DESKTOP_FFMPEG_GDI, - DT_DESKTOP_FFMPEG_DSHOW, - DT_DESKTOP_WIN_GDI, - DT_DESKTOP_WIN_DUPLICATION, - DT_DESKTOP_WIN_WGC, - DT_DESKTOP_WIN_MAG -} RECORD_DESKTOP_TYPES; - -/* - * Record desktop data type - * - */ - -typedef enum { - AT_DESKTOP_NO = 0, - AT_DESKTOP_RGBA, - AT_DESKTOP_BGRA -} RECORD_DESKTOP_DATA_TYPES; - -/** - * Record desktop rect - * - */ - -typedef struct { - int left; - int top; - int right; - int bottom; -} RECORD_DESKTOP_RECT; - -namespace am { -typedef std::function cb_desktop_data; -typedef std::function cb_desktop_error; - -class record_desktop { - public: - record_desktop(); - virtual ~record_desktop(); - - virtual int init(const RECORD_DESKTOP_RECT &rect, const int fps) = 0; - - virtual int start() = 0; - virtual int pause() = 0; - virtual int resume() = 0; - virtual int stop() = 0; - - inline const AVRational &get_time_base() { return _time_base; } - - inline int64_t get_start_time() { return _start_time; } - - inline AVPixelFormat get_pixel_fmt() { return _pixel_fmt; } - - public: - inline bool is_recording() { return _running; } - inline const std::string &get_device_name() { return _device_name; } - inline const RECORD_DESKTOP_DATA_TYPES get_data_type() { return _data_type; } - inline void registe_cb(cb_desktop_data on_data, cb_desktop_error on_error) { - _on_data = on_data; - _on_error = on_error; - } - inline const RECORD_DESKTOP_RECT &get_rect() { return _rect; } - - inline const int get_frame_rate() { return _fps; } - - protected: - virtual void clean_up() = 0; - - protected: - std::atomic_bool _running; - std::atomic_bool _paused; - std::atomic_bool _inited; - - std::thread _thread; - - std::string _device_name; - - RECORD_DESKTOP_RECT _rect; - RECORD_DESKTOP_DATA_TYPES _data_type; - - int _fps; - - cb_desktop_data _on_data; - cb_desktop_error _on_error; - - AVRational _time_base; - int64_t _start_time; - AVPixelFormat _pixel_fmt; -}; -} // namespace am - -#endif \ No newline at end of file diff --git a/dll/record_desktop_wgc.cpp b/dll/record_desktop_wgc.cpp deleted file mode 100644 index 0058da7..0000000 --- a/dll/record_desktop_wgc.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "record_desktop_wgc.h" - -#include "error_define.h" - -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; - - if (info_ex.dwFlags & MONITORINFOF_PRIMARY) { - *(HMONITOR *)data = hmonitor; - } - - return true; -} - -HMONITOR GetPrimaryMonitor() { - HMONITOR hmonitor = nullptr; - - ::EnumDisplayMonitors(NULL, NULL, EnumMonitorProc, (LPARAM)&hmonitor); - - return hmonitor; -} - -namespace am { - -record_desktop_wgc::record_desktop_wgc() {} - -record_desktop_wgc::~record_desktop_wgc() { - stop(); - clean_up(); -} - -int record_desktop_wgc::init(const RECORD_DESKTOP_RECT &rect, const int fps) { - int error = AE_NO; - 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; - - do { - if (!wgc_is_supported()) { - error = AE_UNSUPPORT; - break; - } - - session_ = wgc_create_session(); - if (!session_) { - error = AE_WGC_CREATE_CAPTURER_FAILED; - break; - } - - session_->register_observer(this); - - error = session_->initialize(GetPrimaryMonitor()); - - _inited = true; - } while (0); - - if (error != AE_NO) { - } - - return error; -} - -int record_desktop_wgc::start() { - if (_running == true) { - // al_warn("record desktop duplication is already running"); - return AE_NO; - } - - if (_inited == false) { - return AE_NEED_INIT; - } - - _running = true; - session_->start(); - - return AE_NO; -} - -int record_desktop_wgc::pause() { - _paused = true; - if (session_) session_->pause(); - return AE_NO; -} - -int record_desktop_wgc::resume() { - _paused = false; - if (session_) session_->resume(); - return AE_NO; -} - -int record_desktop_wgc::stop() { - _running = false; - - if (session_) session_->stop(); - - return AE_NO; -} - -void record_desktop_wgc::on_frame(const wgc_session::wgc_session_frame &frame) { - // al_debug("wgc on frame"); - 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(av_frame); - - av_frame_free(&av_frame); -} - -void record_desktop_wgc::clean_up() { - _inited = false; - - if (session_) session_->release(); - - session_ = nullptr; -} - -} // namespace am \ No newline at end of file diff --git a/dll/record_desktop_wgc.h b/dll/record_desktop_wgc.h deleted file mode 100644 index 4c5adc1..0000000 --- a/dll/record_desktop_wgc.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -#include "export.h" -#include "record_desktop.h" - -namespace am { -class record_desktop_wgc : public record_desktop, - public wgc_session::wgc_session_observer { - class wgc_session_module { - using func_type_is_supported = bool (*)(); - using func_type_create_session = wgc_session *(*)(); - - public: - wgc_session_module() { - module_ = ::LoadLibraryA("WGC.dll"); - if (module_) { - func_is_supported_ = (func_type_is_supported)::GetProcAddress( - module_, "wgc_is_supported"); - func_create_session_ = (func_type_create_session)::GetProcAddress( - module_, "wgc_create_session"); - } - } - ~wgc_session_module() { - if (module_) ::FreeModule(module_); - } - - bool is_supported() const { - return func_create_session_ && func_is_supported_(); - } - - wgc_session *create_session() const { - if (!func_create_session_) return nullptr; - - return func_create_session_(); - } - - private: - HMODULE module_ = nullptr; - func_type_is_supported func_is_supported_ = nullptr; - func_type_create_session func_create_session_ = nullptr; - }; - - public: - record_desktop_wgc(); - ~record_desktop_wgc(); - - int init(const RECORD_DESKTOP_RECT &rect, const int fps) override; - - int start() override; - int pause() override; - int resume() override; - int stop() override; - - void on_frame(const wgc_session::wgc_session_frame &frame) override; - - protected: - void clean_up() override; - - private: - wgc_session *session_ = nullptr; - wgc_session_module module_; -}; -} // namespace am \ No newline at end of file diff --git a/dll/screen_capture_wgc.cpp b/dll/screen_capture_wgc.cpp new file mode 100644 index 0000000..80a4877 --- /dev/null +++ b/dll/screen_capture_wgc.cpp @@ -0,0 +1,202 @@ +#include "screen_capture_wgc.h" + +#include +#include +#include + +#include + +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; + + if (info_ex.dwFlags & MONITORINFOF_PRIMARY) { + *(HMONITOR *)data = hmonitor; + } + + return true; +} + +HMONITOR GetPrimaryMonitor() { + HMONITOR hmonitor = nullptr; + + ::EnumDisplayMonitors(NULL, NULL, EnumMonitorProc, (LPARAM)&hmonitor); + + return hmonitor; +} + +ScreenCaptureWgc::ScreenCaptureWgc() {} + +ScreenCaptureWgc::~ScreenCaptureWgc() { + Stop(); + CleanUp(); +} + +bool ScreenCaptureWgc::IsWgcSupported() { + try { + /* no contract for IGraphicsCaptureItemInterop, verify 10.0.18362.0 */ + return winrt::Windows::Foundation::Metadata::ApiInformation:: + IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 8); + } catch (const winrt::hresult_error &) { + return false; + } catch (...) { + return false; + } +} + +int ScreenCaptureWgc::Init(const RECORD_DESKTOP_RECT &rect, const int fps, + cb_desktop_data cb) { + int error = 0; + 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 { + if (!IsWgcSupported()) { + std::cout << "AE_UNSUPPORT" << std::endl; + error = 2; + break; + } + + session_ = new WgcSessionImpl(); + if (!session_) { + error = -1; + std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl; + break; + } + + session_->RegisterObserver(this); + + error = session_->Initialize(GetPrimaryMonitor()); + + _inited = true; + } while (0); + + if (error != 0) { + } + + return error; +} + +int ScreenCaptureWgc::Start() { + if (_running == true) { + std::cout << "record desktop duplication is already running" << std::endl; + return 0; + } + + if (_inited == false) { + std::cout << "AE_NEED_INIT" << std::endl; + return 4; + } + + _running = true; + session_->Start(); + + return 0; +} + +int ScreenCaptureWgc::Pause() { + _paused = true; + if (session_) session_->Pause(); + return 0; +} + +int ScreenCaptureWgc::Resume() { + _paused = false; + if (session_) session_->Resume(); + return 0; +} + +int ScreenCaptureWgc::Stop() { + _running = false; + + if (session_) session_->Stop(); + + return 0; +} + +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 *)av_frame->data, av_frame->pkt_size, 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() { + _inited = false; + + if (session_) session_->Release(); + + session_ = nullptr; +} diff --git a/dll/screen_capture_wgc.h b/dll/screen_capture_wgc.h new file mode 100644 index 0000000..6a5ab86 --- /dev/null +++ b/dll/screen_capture_wgc.h @@ -0,0 +1,76 @@ +#ifndef _SCREEN_CAPTURE_WGC_H_ +#define _SCREEN_CAPTURE_WGC_H_ + +#include + +#include "wgc_session.h" +#include "wgc_session_impl.h" + +extern "C" { +#include +#include +#include +#include +#include +#include +} + +#include +#include +#include +#include + +typedef struct { + int left; + int top; + int right; + int bottom; +} RECORD_DESKTOP_RECT; + +typedef std::function cb_desktop_data; +typedef std::function cb_desktop_error; + +class ScreenCaptureWgc : public WgcSession::wgc_session_observer { + public: + ScreenCaptureWgc(); + ~ScreenCaptureWgc(); + + public: + bool IsWgcSupported(); + + int Init(const RECORD_DESKTOP_RECT &rect, const int fps, cb_desktop_data cb); + + int Start(); + int Pause(); + int Resume(); + int Stop(); + + void OnFrame(const WgcSession::wgc_session_frame &frame); + + protected: + void CleanUp(); + + private: + WgcSession *session_ = nullptr; + + std::atomic_bool _running; + std::atomic_bool _paused; + std::atomic_bool _inited; + + std::thread _thread; + + std::string _device_name; + + RECORD_DESKTOP_RECT _rect; + + int _fps; + + 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/dll/wgc_session.h new file mode 100644 index 0000000..d7a3ebc --- /dev/null +++ b/dll/wgc_session.h @@ -0,0 +1,40 @@ +#ifndef _WGC_SESSION_H_ +#define _WGC_SESSION_H_ + +#include + +class WgcSession { + public: + struct wgc_session_frame { + unsigned int width; + unsigned int height; + unsigned int row_pitch; + + const unsigned char *data; + }; + + class wgc_session_observer { + public: + virtual ~wgc_session_observer() {} + virtual void OnFrame(const wgc_session_frame &frame) = 0; + }; + + public: + virtual void Release() = 0; + + virtual int Initialize(HWND hwnd) = 0; + virtual int Initialize(HMONITOR hmonitor) = 0; + + virtual void RegisterObserver(wgc_session_observer *observer) = 0; + + virtual int Start() = 0; + virtual int Stop() = 0; + + virtual int Pause() = 0; + virtual int Resume() = 0; + + protected: + virtual ~WgcSession(){}; +}; + +#endif \ No newline at end of file diff --git a/dll/wgc_session_impl.cpp b/dll/wgc_session_impl.cpp index 9a2916d..260de7f 100644 --- a/dll/wgc_session_impl.cpp +++ b/dll/wgc_session_impl.cpp @@ -1,15 +1,21 @@ -#include "pch.h" +#include "wgc_session_impl.h" +#include + +#include #include +#include #include -#define CHECK_INIT \ - if (!is_initialized_) \ - return AM_ERROR::AE_NEED_INIT +#define CHECK_INIT \ + if (!is_initialized_) { \ + std::cout << "AE_NEED_INIT" << std::endl; \ + return 4; \ + } -#define CHECK_CLOSED \ - if (cleaned_.load() == true) { \ - throw winrt::hresult_error(RO_E_CLOSED); \ +#define CHECK_CLOSED \ + if (cleaned_.load() == true) { \ + throw winrt::hresult_error(RO_E_CLOSED); \ } extern "C" { @@ -17,45 +23,42 @@ HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice( ::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice); } -namespace am { +WgcSessionImpl::WgcSessionImpl() {} -wgc_session_impl::wgc_session_impl() {} - -wgc_session_impl::~wgc_session_impl() { - stop(); - cleanup(); +WgcSessionImpl::~WgcSessionImpl() { + Stop(); + CleanUp(); } -void wgc_session_impl::release() { delete this; } +void WgcSessionImpl::Release() { delete this; } -int wgc_session_impl::initialize(HWND hwnd) { +int WgcSessionImpl::Initialize(HWND hwnd) { std::lock_guard locker(lock_); target_.hwnd = hwnd; target_.is_window = true; - return initialize(); + return Initialize(); } -int wgc_session_impl::initialize(HMONITOR hmonitor) { +int WgcSessionImpl::Initialize(HMONITOR hmonitor) { std::lock_guard locker(lock_); target_.hmonitor = hmonitor; target_.is_window = false; - return initialize(); + return Initialize(); } -void wgc_session_impl::register_observer(wgc_session_observer *observer) { +void WgcSessionImpl::RegisterObserver(wgc_session_observer *observer) { std::lock_guard locker(lock_); observer_ = observer; } -int wgc_session_impl::start() { +int WgcSessionImpl::Start() { std::lock_guard locker(lock_); - if (is_running_) - return AM_ERROR::AE_NO; + if (is_running_) return 0; - int error = AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED; + int error = 1; CHECK_INIT; try { @@ -70,106 +73,95 @@ int wgc_session_impl::start() { capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_); capture_frame_size_ = current_size; capture_framepool_trigger_ = capture_framepool_.FrameArrived( - winrt::auto_revoke, {this, &wgc_session_impl::on_frame}); + winrt::auto_revoke, {this, &WgcSessionImpl::OnFrame}); capture_close_trigger_ = capture_item_.Closed( - winrt::auto_revoke, {this, &wgc_session_impl::on_closed}); + winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed}); } - if (!capture_framepool_) - throw std::exception(); + if (!capture_framepool_) throw std::exception(); is_running_ = true; // we do not need to crate a thread to enter a message loop coz we use // CreateFreeThreaded instead of Create to create a capture frame pool, // we need to test the performance later - // loop_ = std::thread(std::bind(&wgc_session_impl::message_func, this)); + // loop_ = std::thread(std::bind(&WgcSessionImpl::message_func, this)); capture_session_.StartCapture(); - error = AM_ERROR::AE_NO; + error = 0; } catch (winrt::hresult_error) { - return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED; + std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl; + return 86; } catch (...) { - return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED; + return 86; } return error; } -int wgc_session_impl::stop() { +int WgcSessionImpl::Stop() { std::lock_guard locker(lock_); CHECK_INIT; is_running_ = false; - if (loop_.joinable()) - loop_.join(); + // if (loop_.joinable()) loop_.join(); - if (capture_framepool_trigger_) - capture_framepool_trigger_.revoke(); + if (capture_framepool_trigger_) capture_framepool_trigger_.revoke(); if (capture_session_) { capture_session_.Close(); capture_session_ = nullptr; } - return AM_ERROR::AE_NO; + return 0; } -int wgc_session_impl::pause() { +int WgcSessionImpl::Pause() { std::lock_guard locker(lock_); CHECK_INIT; - return AM_ERROR::AE_NO; + return 0; } -int wgc_session_impl::resume() { +int WgcSessionImpl::Resume() { std::lock_guard locker(lock_); CHECK_INIT; - return AM_ERROR::AE_NO; + return 0; } -auto wgc_session_impl::create_d3d11_device() { - auto create_d3d_device = [](D3D_DRIVER_TYPE const type, - winrt::com_ptr &device) { - WINRT_ASSERT(!device); +auto WgcSessionImpl::CreateD3D11Device() { + winrt::com_ptr d3d_device; + HRESULT hr; - UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + WINRT_ASSERT(!d3d_device); - //#ifdef _DEBUG - // flags |= D3D11_CREATE_DEVICE_DEBUG; - //#endif + D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_HARDWARE; + UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0, + D3D11_SDK_VERSION, d3d_device.put(), nullptr, nullptr); - return ::D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0, - D3D11_SDK_VERSION, device.put(), nullptr, - nullptr); - }; - auto create_d3d_device_wrapper = [&create_d3d_device]() { - winrt::com_ptr device; - HRESULT hr = create_d3d_device(D3D_DRIVER_TYPE_HARDWARE, device); + if (DXGI_ERROR_UNSUPPORTED == hr) { + // change D3D_DRIVER_TYPE + D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_WARP; + hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0, + D3D11_SDK_VERSION, d3d_device.put(), nullptr, + nullptr); + } - if (DXGI_ERROR_UNSUPPORTED == hr) { - hr = create_d3d_device(D3D_DRIVER_TYPE_WARP, device); - } - - winrt::check_hresult(hr); - return device; - }; - - auto d3d_device = create_d3d_device_wrapper(); - auto dxgi_device = d3d_device.as(); + winrt::check_hresult(hr); winrt::com_ptr<::IInspectable> d3d11_device; winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice( - dxgi_device.get(), d3d11_device.put())); + d3d_device.as().get(), d3d11_device.put())); return d3d11_device .as(); } -auto wgc_session_impl::create_capture_item(HWND hwnd) { +auto WgcSessionImpl::CreateCaptureItemForWindow(HWND hwnd) { auto activation_factory = winrt::get_activation_factory< winrt::Windows::Graphics::Capture::GraphicsCaptureItem>(); auto interop_factory = activation_factory.as(); @@ -181,7 +173,7 @@ auto wgc_session_impl::create_capture_item(HWND hwnd) { return item; } -auto wgc_session_impl::create_capture_item(HMONITOR hmonitor) { +auto WgcSessionImpl::CreateCaptureItemForMonitor(HMONITOR hmonitor) { auto activation_factory = winrt::get_activation_factory< winrt::Windows::Graphics::Capture::GraphicsCaptureItem>(); auto interop_factory = activation_factory.as(); @@ -193,10 +185,9 @@ auto wgc_session_impl::create_capture_item(HMONITOR hmonitor) { return item; } -HRESULT wgc_session_impl::create_mapped_texture( +HRESULT WgcSessionImpl::CreateMappedTexture( winrt::com_ptr src_texture, unsigned int width, unsigned int height) { - D3D11_TEXTURE2D_DESC src_desc; src_texture->GetDesc(&src_desc); D3D11_TEXTURE2D_DESC map_desc; @@ -211,13 +202,14 @@ HRESULT wgc_session_impl::create_mapped_texture( map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; map_desc.MiscFlags = 0; - auto d3dDevice = get_dxgi_interface(d3d11_direct_device_); + auto d3dDevice = + GetDXGIInterfaceFromObject(d3d11_direct_device_); return d3dDevice->CreateTexture2D(&map_desc, nullptr, d3d11_texture_mapped_.put()); } -void wgc_session_impl::on_frame( +void WgcSessionImpl::OnFrame( winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const &sender, winrt::Windows::Foundation::IInspectable const &args) { std::lock_guard locker(lock_); @@ -240,10 +232,10 @@ void wgc_session_impl::on_frame( // copy to mapped texture { auto frame_captured = - get_dxgi_interface(frame.Surface()); + GetDXGIInterfaceFromObject(frame.Surface()); if (!d3d11_texture_mapped_ || is_new_size) - create_mapped_texture(frame_captured); + CreateMappedTexture(frame_captured); d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(), frame_captured.get()); @@ -262,61 +254,12 @@ void wgc_session_impl::on_frame( // copy data from map_result.pData if (map_result.pData && observer_) { - observer_->on_frame(wgc_session_frame{ + observer_->OnFrame(wgc_session_frame{ static_cast(frame_size.Width), static_cast(frame_size.Height), map_result.RowPitch, const_cast( (unsigned char *)map_result.pData)}); } -#if 0 - if (map_result.pData) { - static unsigned char *buffer = nullptr; - if (buffer && is_new_size) - delete[] buffer; - - if (!buffer) - buffer = new unsigned char[frame_size.Width * frame_size.Height * 4]; - - int dstRowPitch = frame_size.Width * 4; - for (int h = 0; h < frame_size.Height; h++) { - memcpy_s(buffer + h * dstRowPitch, dstRowPitch, - (BYTE *)map_result.pData + h * map_result.RowPitch, - min(map_result.RowPitch, dstRowPitch)); - } - - BITMAPINFOHEADER bi; - - bi.biSize = sizeof(BITMAPINFOHEADER); - bi.biWidth = frame_size.Width; - bi.biHeight = frame_size.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 + frame_size.Width * frame_size.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, frame_size.Width * frame_size.Height * 4, fp); - - fflush(fp); - fclose(fp); - } -#endif d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0); } @@ -330,41 +273,44 @@ void wgc_session_impl::on_frame( } } -void wgc_session_impl::on_closed( +void WgcSessionImpl::OnClosed( winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &, winrt::Windows::Foundation::IInspectable const &) { - OutputDebugStringW(L"wgc_session_impl::on_closed"); + OutputDebugStringW(L"WgcSessionImpl::OnClosed"); } -int wgc_session_impl::initialize() { - if (is_initialized_) - return AM_ERROR::AE_NO; +int WgcSessionImpl::Initialize() { + if (is_initialized_) return 0; - if (!(d3d11_direct_device_ = create_d3d11_device())) - return AM_ERROR::AE_D3D_CREATE_DEVICE_FAILED; + if (!(d3d11_direct_device_ = CreateD3D11Device())) { + std::cout << "AE_D3D_CREATE_DEVICE_FAILED" << std::endl; + return 1; + } try { if (target_.is_window) - capture_item_ = create_capture_item(target_.hwnd); + capture_item_ = CreateCaptureItemForWindow(target_.hwnd); else - capture_item_ = create_capture_item(target_.hmonitor); + capture_item_ = CreateCaptureItemForMonitor(target_.hmonitor); // Set up - auto d3d11_device = get_dxgi_interface(d3d11_direct_device_); + auto d3d11_device = + GetDXGIInterfaceFromObject(d3d11_direct_device_); d3d11_device->GetImmediateContext(d3d11_device_context_.put()); } catch (winrt::hresult_error) { - return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED; + std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl; + return 86; } catch (...) { - return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED; + return 86; } is_initialized_ = true; - return AM_ERROR::AE_NO; + return 0; } -void wgc_session_impl::cleanup() { +void WgcSessionImpl::CleanUp() { std::lock_guard locker(lock_); auto expected = false; @@ -372,11 +318,9 @@ void wgc_session_impl::cleanup() { capture_close_trigger_.revoke(); capture_framepool_trigger_.revoke(); - if (capture_framepool_) - capture_framepool_.Close(); + if (capture_framepool_) capture_framepool_.Close(); - if (capture_session_) - capture_session_.Close(); + if (capture_session_) capture_session_.Close(); capture_framepool_ = nullptr; capture_session_ = nullptr; @@ -391,35 +335,32 @@ LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param, return DefWindowProc(window, message, w_param, l_param); } -void wgc_session_impl::message_func() { - const std::wstring kClassName = L"am_fake_window"; +// void WgcSessionImpl::message_func() { +// const std::wstring kClassName = L"am_fake_window"; - WNDCLASS wc = {}; +// WNDCLASS wc = {}; - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = DefWindowProc; - wc.hCursor = LoadCursor(nullptr, IDC_ARROW); - wc.hbrBackground = reinterpret_cast(COLOR_WINDOW); - wc.lpszClassName = kClassName.c_str(); +// wc.style = CS_HREDRAW | CS_VREDRAW; +// wc.lpfnWndProc = DefWindowProc; +// wc.hCursor = LoadCursor(nullptr, IDC_ARROW); +// wc.hbrBackground = reinterpret_cast(COLOR_WINDOW); +// wc.lpszClassName = kClassName.c_str(); - if (!::RegisterClassW(&wc)) - return; +// if (!::RegisterClassW(&wc)) return; - hwnd_ = ::CreateWindowW(kClassName.c_str(), nullptr, WS_OVERLAPPEDWINDOW, 0, - 0, 0, 0, nullptr, nullptr, nullptr, nullptr); - MSG msg; - while (is_running_) { - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - if (!is_running_) - break; - TranslateMessage(&msg); - DispatchMessage(&msg); - } - Sleep(10); - } +// hwnd_ = ::CreateWindowW(kClassName.c_str(), nullptr, WS_OVERLAPPEDWINDOW, +// 0, +// 0, 0, 0, nullptr, nullptr, nullptr, nullptr); +// MSG msg; +// while (is_running_) { +// while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { +// if (!is_running_) break; +// TranslateMessage(&msg); +// DispatchMessage(&msg); +// } +// Sleep(10); +// } - ::CloseWindow(hwnd_); - ::DestroyWindow(hwnd_); -} - -} // namespace am \ No newline at end of file +// ::CloseWindow(hwnd_); +// ::DestroyWindow(hwnd_); +// } \ No newline at end of file diff --git a/dll/wgc_session_impl.h b/dll/wgc_session_impl.h index 7b912c0..f3c622c 100644 --- a/dll/wgc_session_impl.h +++ b/dll/wgc_session_impl.h @@ -1,15 +1,31 @@ -#pragma once +#ifndef _WGC_SESSION_IMPL_H_ +#define _WGC_SESSION_IMPL_H_ + +#include +#include +#include #include #include -namespace am { -class wgc_session_impl : public wgc_session { +#include "wgc_session.h" + +class WgcSessionImpl : public WgcSession { struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1")) IDirect3DDxgiInterfaceAccess : ::IUnknown { virtual HRESULT __stdcall GetInterface(GUID const &id, void **object) = 0; }; + template + inline 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; + } + struct { union { HWND hwnd; @@ -18,47 +34,44 @@ class wgc_session_impl : public wgc_session { bool is_window; } target_{0}; -public: - wgc_session_impl(); - ~wgc_session_impl() override; + public: + WgcSessionImpl(); + ~WgcSessionImpl() override; -public: - void release() override; + public: + void Release() override; - int initialize(HWND hwnd) override; - int initialize(HMONITOR hmonitor) override; + int Initialize(HWND hwnd) override; + int Initialize(HMONITOR hmonitor) override; - void register_observer(wgc_session_observer *observer) override; + void RegisterObserver(wgc_session_observer *observer) override; - int start() override; - int stop() override; + int Start() override; + int Stop() override; - int pause() override; - int resume() override; + int Pause() override; + int Resume() override; -private: - auto create_d3d11_device(); - auto create_capture_item(HWND hwnd); - auto create_capture_item(HMONITOR hmonitor); - template - auto - get_dxgi_interface(winrt::Windows::Foundation::IInspectable const &object); - HRESULT create_mapped_texture(winrt::com_ptr src_texture, - unsigned int width = 0, - unsigned int height = 0); - void - on_frame(winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const - &sender, - winrt::Windows::Foundation::IInspectable const &args); - void on_closed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &, - winrt::Windows::Foundation::IInspectable const &); + private: + auto CreateD3D11Device(); + auto CreateCaptureItemForWindow(HWND hwnd); + auto CreateCaptureItemForMonitor(HMONITOR hmonitor); - int initialize(); - void cleanup(); + HRESULT CreateMappedTexture(winrt::com_ptr src_texture, + unsigned int width = 0, unsigned int height = 0); + void OnFrame( + winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const + &sender, + winrt::Windows::Foundation::IInspectable const &args); + void OnClosed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &, + winrt::Windows::Foundation::IInspectable const &); - void message_func(); + int Initialize(); + void CleanUp(); -private: + // void message_func(); + + private: std::mutex lock_; bool is_initialized_ = false; bool is_running_ = false; @@ -90,15 +103,14 @@ private: HWND hwnd_ = nullptr; }; -template -inline auto wgc_session_impl::get_dxgi_interface( - 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; -} +// template +// inline auto WgcSessionImpl::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; +// } - -} // namespace am \ No newline at end of file +#endif \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index cec55fa..b2d4175 100644 --- a/xmake.lua +++ b/xmake.lua @@ -11,9 +11,9 @@ add_requires("spdlog 1.11.0", "ffmpeg 5.1.2", {system = false}) add_defines("UNICODE") if is_os("windows") then - -- add_ldflags("/SUBSYSTEM:CONSOLE") + add_ldflags("/SUBSYSTEM:CONSOLE") add_links("Shell32", "windowsapp", "dwmapi", "User32", "kernel32") - -- add_requires("vcpkg::sdl2") + add_requires("vcpkg::sdl2 2.26.4") elseif is_os("linux") then add_links("pthread") set_config("cxxflags", "-fPIC") @@ -34,7 +34,11 @@ target("remote_desk") add_deps("projectx") add_packages("log") add_packages("ffmpeg") + add_packages("vcpkg::sdl2") add_links("avfilter", "avdevice", "avformat", "avcodec", "swscale", "swresample", "avutil") add_files("dll/*.cpp") add_includedirs("../../src/interface") - -- add_links("SDL2main", "SDL2-static") + add_links("SDL2-static", "SDL2main", "Shell32", "gdi32", "winmm", + "setupapi", "version", "WindowsApp", "Imm32", "avutil") + +