Use sdl2 to display capture screen

This commit is contained in:
dijunkun
2023-08-29 17:33:58 +08:00
parent 76a80e6d07
commit ae67ad961e
18 changed files with 624 additions and 949 deletions

View File

@@ -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<ID3D11Texture2D>(frame.Surface());
com_ptr<ID3D11Texture2D> backBuffer;
check_hresult(m_swapChain->GetBuffer(0, guid_of<ID3D11Texture2D>(),
backBuffer.put_void()));
@@ -123,8 +123,7 @@ void SimpleCapture::OnFrameArrived(
auto frameSurface =
GetDXGIInterfaceFromObject<ID3D11Texture2D>(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 *

View File

@@ -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

View File

@@ -1,17 +0,0 @@
#include "pch.h"
#include <winrt/Windows.Foundation.Metadata.h>
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(); }

View File

@@ -1,50 +0,0 @@
#pragma once
#include <Windows.h>
#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();

View File

@@ -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

View File

@@ -1,19 +1,91 @@
#define AMRECORDER_IMPORT
#include <stdio.h>
#include <chrono>
#include <iostream>
#include <thread>
#include "export.h"
#include "head.h"
#include "record_desktop_wgc.h"
#include "screen_capture_wgc.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
};
#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,14 +93,50 @@ 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;

View File

@@ -1 +0,0 @@
#include "pch.h"

View File

@@ -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 <Unknwn.h>
#include <inspectable.h>
// WinRT
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.System.h>
#include <winrt/Windows.Graphics.DirectX.h>
#include <winrt/Windows.Graphics.DirectX.Direct3d11.h>
#include <winrt/Windows.Graphics.Capture.h>
#include <Windows.Graphics.Capture.Interop.h>
#include <DispatcherQueue.h>
// STL
#include <atomic>
#include <memory>
// D3D
#include <d3d11_4.h>
#include <dxgi1_6.h>
#include <d2d1_3.h>
#include <wincodec.h>
// windowws
#include <Windows.h>
#include "error_define.h"
#include "export.h"
#include "wgc_session_impl.h"
#endif // PCH_H

View File

@@ -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()
{
}

View File

@@ -1,124 +0,0 @@
#ifndef RECORD_DESKTOP
#define RECORD_DESKTOP
extern "C" {
#include <libavcodec\adts_parser.h>
#include <libavcodec\avcodec.h>
#include <libavdevice\avdevice.h>
#include <libavfilter\avfilter.h>
#include <libavfilter\buffersink.h>
#include <libavfilter\buffersrc.h>
#include <libavformat\avformat.h>
#include <libavutil\avassert.h>
#include <libavutil\channel_layout.h>
#include <libavutil\error.h>
#include <libavutil\imgutils.h>
#include <libavutil\log.h>
#include <libavutil\mathematics.h>
#include <libavutil\opt.h>
#include <libavutil\samplefmt.h>
#include <libavutil\time.h>
#include <libavutil\timestamp.h>
#include <libswresample\swresample.h>
#include <libswscale\swscale.h>
}
#include <atomic>
#include <functional>
#include <string>
#include <thread>
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<void(AVFrame *frame)> cb_desktop_data;
typedef std::function<void(int)> 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

View File

@@ -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

View File

@@ -1,65 +0,0 @@
#pragma once
#include <Windows.h>
#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

202
dll/screen_capture_wgc.cpp Normal file
View File

@@ -0,0 +1,202 @@
#include "screen_capture_wgc.h"
#include <d3d11_4.h>
#include <winrt/Windows.Foundation.Metadata.h>
#include <winrt/Windows.Graphics.Capture.h>
#include <iostream>
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;
}

76
dll/screen_capture_wgc.h Normal file
View File

@@ -0,0 +1,76 @@
#ifndef _SCREEN_CAPTURE_WGC_H_
#define _SCREEN_CAPTURE_WGC_H_
#include <Windows.h>
#include "wgc_session.h"
#include "wgc_session_impl.h"
extern "C" {
#include <libavcodec\avcodec.h>
#include <libavfilter\avfilter.h>
#include <libavformat\avformat.h>
#include <libavutil\imgutils.h>
#include <libavutil\time.h>
#include <libswscale/swscale.h>
}
#include <atomic>
#include <functional>
#include <string>
#include <thread>
typedef struct {
int left;
int top;
int right;
int bottom;
} RECORD_DESKTOP_RECT;
typedef std::function<void(unsigned char *, int, int, int)> cb_desktop_data;
typedef std::function<void(int)> 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

40
dll/wgc_session.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef _WGC_SESSION_H_
#define _WGC_SESSION_H_
#include <Windows.h>
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

View File

@@ -1,11 +1,17 @@
#include "pch.h"
#include "wgc_session_impl.h"
#include <Windows.Graphics.Capture.Interop.h>
#include <atomic>
#include <functional>
#include <iostream>
#include <memory>
#define CHECK_INIT \
if (!is_initialized_) \
return AM_ERROR::AE_NEED_INIT
if (!is_initialized_) { \
std::cout << "AE_NEED_INIT" << std::endl; \
return 4; \
}
#define CHECK_CLOSED \
if (cleaned_.load() == true) { \
@@ -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<ID3D11Device> &device) {
WINRT_ASSERT(!device);
auto WgcSessionImpl::CreateD3D11Device() {
winrt::com_ptr<ID3D11Device> d3d_device;
HRESULT hr;
WINRT_ASSERT(!d3d_device);
D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_HARDWARE;
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);
};
auto create_d3d_device_wrapper = [&create_d3d_device]() {
winrt::com_ptr<ID3D11Device> device;
HRESULT hr = create_d3d_device(D3D_DRIVER_TYPE_HARDWARE, device);
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);
// 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);
}
winrt::check_hresult(hr);
return device;
};
auto d3d_device = create_d3d_device_wrapper();
auto dxgi_device = d3d_device.as<IDXGIDevice>();
winrt::com_ptr<::IInspectable> d3d11_device;
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(
dxgi_device.get(), d3d11_device.put()));
d3d_device.as<IDXGIDevice>().get(), d3d11_device.put()));
return d3d11_device
.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
}
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<IGraphicsCaptureItemInterop>();
@@ -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<IGraphicsCaptureItemInterop>();
@@ -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<ID3D11Texture2D> 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<ID3D11Device>(d3d11_direct_device_);
auto d3dDevice =
GetDXGIInterfaceFromObject<ID3D11Device>(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<ID3D11Texture2D>(frame.Surface());
GetDXGIInterfaceFromObject<ID3D11Texture2D>(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<unsigned int>(frame_size.Width),
static_cast<unsigned int>(frame_size.Height), map_result.RowPitch,
const_cast<const unsigned char *>(
(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<ID3D11Device>(d3d11_direct_device_);
auto d3d11_device =
GetDXGIInterfaceFromObject<ID3D11Device>(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<HBRUSH>(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<HBRUSH>(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
// ::CloseWindow(hwnd_);
// ::DestroyWindow(hwnd_);
// }

View File

@@ -1,15 +1,31 @@
#pragma once
#ifndef _WGC_SESSION_IMPL_H_
#define _WGC_SESSION_IMPL_H_
#include <d3d11_4.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Graphics.Capture.h>
#include <mutex>
#include <thread>
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 <typename T>
inline auto GetDXGIInterfaceFromObject(
winrt::Windows::Foundation::IInspectable const &object) {
auto access = object.as<IDirect3DDxgiInterfaceAccess>();
winrt::com_ptr<T> result;
winrt::check_hresult(
access->GetInterface(winrt::guid_of<T>(), result.put_void()));
return result;
}
struct {
union {
HWND hwnd;
@@ -19,44 +35,41 @@ class wgc_session_impl : public wgc_session {
} target_{0};
public:
wgc_session_impl();
~wgc_session_impl() override;
WgcSessionImpl();
~WgcSessionImpl() override;
public:
void release() override;
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 <typename T>
auto
get_dxgi_interface(winrt::Windows::Foundation::IInspectable const &object);
HRESULT create_mapped_texture(winrt::com_ptr<ID3D11Texture2D> src_texture,
unsigned int width = 0,
unsigned int height = 0);
void
on_frame(winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const
auto CreateD3D11Device();
auto CreateCaptureItemForWindow(HWND hwnd);
auto CreateCaptureItemForMonitor(HMONITOR hmonitor);
HRESULT CreateMappedTexture(winrt::com_ptr<ID3D11Texture2D> 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 on_closed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
void OnClosed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
winrt::Windows::Foundation::IInspectable const &);
int initialize();
void cleanup();
int Initialize();
void CleanUp();
void message_func();
// void message_func();
private:
std::mutex lock_;
@@ -90,15 +103,14 @@ private:
HWND hwnd_ = nullptr;
};
template <typename T>
inline auto wgc_session_impl::get_dxgi_interface(
winrt::Windows::Foundation::IInspectable const &object) {
auto access = object.as<IDirect3DDxgiInterfaceAccess>();
winrt::com_ptr<T> result;
winrt::check_hresult(
access->GetInterface(winrt::guid_of<T>(), result.put_void()));
return result;
}
// template <typename T>
// inline auto WgcSessionImpl::GetDXGIInterfaceFromObject(
// winrt::Windows::Foundation::IInspectable const &object) {
// auto access = object.as<IDirect3DDxgiInterfaceAccess>();
// winrt::com_ptr<T> result;
// winrt::check_hresult(
// access->GetInterface(winrt::guid_of<T>(), result.put_void()));
// return result;
// }
} // namespace am
#endif

View File

@@ -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")