mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35:34 +08:00
Use sdl2 to display capture screen
This commit is contained in:
@@ -12,9 +12,10 @@
|
|||||||
//
|
//
|
||||||
//*********************************************************
|
//*********************************************************
|
||||||
|
|
||||||
#include "pch.h"
|
|
||||||
#include "SimpleCapture.h"
|
#include "SimpleCapture.h"
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
using namespace winrt;
|
using namespace winrt;
|
||||||
using namespace Windows;
|
using namespace Windows;
|
||||||
using namespace Windows::Foundation;
|
using namespace Windows::Foundation;
|
||||||
@@ -107,7 +108,6 @@ void SimpleCapture::OnFrameArrived(
|
|||||||
auto frameSurface =
|
auto frameSurface =
|
||||||
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
||||||
|
|
||||||
|
|
||||||
com_ptr<ID3D11Texture2D> backBuffer;
|
com_ptr<ID3D11Texture2D> backBuffer;
|
||||||
check_hresult(m_swapChain->GetBuffer(0, guid_of<ID3D11Texture2D>(),
|
check_hresult(m_swapChain->GetBuffer(0, guid_of<ID3D11Texture2D>(),
|
||||||
backBuffer.put_void()));
|
backBuffer.put_void()));
|
||||||
@@ -123,8 +123,7 @@ void SimpleCapture::OnFrameArrived(
|
|||||||
auto frameSurface =
|
auto frameSurface =
|
||||||
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
||||||
|
|
||||||
if (!m_mappedTexture || newSize)
|
if (!m_mappedTexture || newSize) CreateMappedTexture(frameSurface);
|
||||||
CreateMappedTexture(frameSurface);
|
|
||||||
|
|
||||||
m_d3dContext->CopyResource(m_mappedTexture.get(), frameSurface.get());
|
m_d3dContext->CopyResource(m_mappedTexture.get(), frameSurface.get());
|
||||||
|
|
||||||
@@ -136,8 +135,7 @@ void SimpleCapture::OnFrameArrived(
|
|||||||
#if 1
|
#if 1
|
||||||
if (mapInfo.pData) {
|
if (mapInfo.pData) {
|
||||||
static unsigned char *buffer = nullptr;
|
static unsigned char *buffer = nullptr;
|
||||||
if (buffer && newSize)
|
if (buffer && newSize) delete[] buffer;
|
||||||
delete[] buffer;
|
|
||||||
|
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
buffer = new unsigned char[frameContentSize.Width *
|
buffer = new unsigned char[frameContentSize.Width *
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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(); }
|
|
||||||
@@ -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();
|
|
||||||
@@ -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
|
|
||||||
@@ -1,19 +1,91 @@
|
|||||||
|
|
||||||
#define AMRECORDER_IMPORT
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "export.h"
|
#include "screen_capture_wgc.h"
|
||||||
#include "head.h"
|
|
||||||
#include "record_desktop_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() {
|
int main() {
|
||||||
// bool is_supported = wgc_is_supported();
|
ScreenCaptureWgc *recorder = new ScreenCaptureWgc();
|
||||||
// if (!wgc_is_supported) {
|
|
||||||
// std::cout << "Not support wgc" << std::endl;
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
static am::record_desktop *recorder = new am::record_desktop_wgc();
|
|
||||||
|
|
||||||
RECORD_DESKTOP_RECT rect;
|
RECORD_DESKTOP_RECT rect;
|
||||||
rect.left = 0;
|
rect.left = 0;
|
||||||
@@ -21,14 +93,50 @@ int main() {
|
|||||||
rect.right = GetSystemMetrics(SM_CXSCREEN);
|
rect.right = GetSystemMetrics(SM_CXSCREEN);
|
||||||
rect.bottom = GetSystemMetrics(SM_CYSCREEN);
|
rect.bottom = GetSystemMetrics(SM_CYSCREEN);
|
||||||
|
|
||||||
recorder->init(rect, 10);
|
recorder->Init(rect, 10, OnFrame);
|
||||||
|
|
||||||
recorder->start();
|
recorder->Start();
|
||||||
// int pause() override;
|
|
||||||
// int resume() override;
|
|
||||||
// int stop() override;
|
|
||||||
|
|
||||||
|
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) {
|
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;
|
return 0;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
#include "pch.h"
|
|
||||||
@@ -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
|
|
||||||
@@ -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()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
application/remote_desk/dll/screen_capture_wgc.cpp
Normal file
202
application/remote_desk/dll/screen_capture_wgc.cpp
Normal 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
application/remote_desk/dll/screen_capture_wgc.h
Normal file
76
application/remote_desk/dll/screen_capture_wgc.h
Normal 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
application/remote_desk/dll/wgc_session.h
Normal file
40
application/remote_desk/dll/wgc_session.h
Normal 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
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
#include "pch.h"
|
#include "wgc_session_impl.h"
|
||||||
|
|
||||||
|
#include <Windows.Graphics.Capture.Interop.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#define CHECK_INIT \
|
#define CHECK_INIT \
|
||||||
if (!is_initialized_) \
|
if (!is_initialized_) { \
|
||||||
return AM_ERROR::AE_NEED_INIT
|
std::cout << "AE_NEED_INIT" << std::endl; \
|
||||||
|
return 4; \
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_CLOSED \
|
#define CHECK_CLOSED \
|
||||||
if (cleaned_.load() == true) { \
|
if (cleaned_.load() == true) { \
|
||||||
@@ -17,45 +23,42 @@ HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(
|
|||||||
::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice);
|
::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace am {
|
WgcSessionImpl::WgcSessionImpl() {}
|
||||||
|
|
||||||
wgc_session_impl::wgc_session_impl() {}
|
WgcSessionImpl::~WgcSessionImpl() {
|
||||||
|
Stop();
|
||||||
wgc_session_impl::~wgc_session_impl() {
|
CleanUp();
|
||||||
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_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
target_.hwnd = hwnd;
|
target_.hwnd = hwnd;
|
||||||
target_.is_window = true;
|
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_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
target_.hmonitor = hmonitor;
|
target_.hmonitor = hmonitor;
|
||||||
target_.is_window = false;
|
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_);
|
std::lock_guard locker(lock_);
|
||||||
observer_ = observer;
|
observer_ = observer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wgc_session_impl::start() {
|
int WgcSessionImpl::Start() {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
if (is_running_)
|
if (is_running_) return 0;
|
||||||
return AM_ERROR::AE_NO;
|
|
||||||
|
|
||||||
int error = AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
int error = 1;
|
||||||
|
|
||||||
CHECK_INIT;
|
CHECK_INIT;
|
||||||
try {
|
try {
|
||||||
@@ -70,106 +73,95 @@ int wgc_session_impl::start() {
|
|||||||
capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
|
capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
|
||||||
capture_frame_size_ = current_size;
|
capture_frame_size_ = current_size;
|
||||||
capture_framepool_trigger_ = capture_framepool_.FrameArrived(
|
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(
|
capture_close_trigger_ = capture_item_.Closed(
|
||||||
winrt::auto_revoke, {this, &wgc_session_impl::on_closed});
|
winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!capture_framepool_)
|
if (!capture_framepool_) throw std::exception();
|
||||||
throw std::exception();
|
|
||||||
|
|
||||||
is_running_ = true;
|
is_running_ = true;
|
||||||
|
|
||||||
// we do not need to crate a thread to enter a message loop coz we use
|
// 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,
|
// CreateFreeThreaded instead of Create to create a capture frame pool,
|
||||||
// we need to test the performance later
|
// 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();
|
capture_session_.StartCapture();
|
||||||
|
|
||||||
error = AM_ERROR::AE_NO;
|
error = 0;
|
||||||
} catch (winrt::hresult_error) {
|
} catch (winrt::hresult_error) {
|
||||||
return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
|
||||||
|
return 86;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
return 86;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wgc_session_impl::stop() {
|
int WgcSessionImpl::Stop() {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
CHECK_INIT;
|
CHECK_INIT;
|
||||||
|
|
||||||
is_running_ = false;
|
is_running_ = false;
|
||||||
|
|
||||||
if (loop_.joinable())
|
// if (loop_.joinable()) loop_.join();
|
||||||
loop_.join();
|
|
||||||
|
|
||||||
if (capture_framepool_trigger_)
|
if (capture_framepool_trigger_) capture_framepool_trigger_.revoke();
|
||||||
capture_framepool_trigger_.revoke();
|
|
||||||
|
|
||||||
if (capture_session_) {
|
if (capture_session_) {
|
||||||
capture_session_.Close();
|
capture_session_.Close();
|
||||||
capture_session_ = nullptr;
|
capture_session_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AM_ERROR::AE_NO;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wgc_session_impl::pause() {
|
int WgcSessionImpl::Pause() {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
CHECK_INIT;
|
CHECK_INIT;
|
||||||
return AM_ERROR::AE_NO;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wgc_session_impl::resume() {
|
int WgcSessionImpl::Resume() {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
CHECK_INIT;
|
CHECK_INIT;
|
||||||
return AM_ERROR::AE_NO;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto wgc_session_impl::create_d3d11_device() {
|
auto WgcSessionImpl::CreateD3D11Device() {
|
||||||
auto create_d3d_device = [](D3D_DRIVER_TYPE const type,
|
winrt::com_ptr<ID3D11Device> d3d_device;
|
||||||
winrt::com_ptr<ID3D11Device> &device) {
|
HRESULT hr;
|
||||||
WINRT_ASSERT(!device);
|
|
||||||
|
|
||||||
|
WINRT_ASSERT(!d3d_device);
|
||||||
|
|
||||||
|
D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_HARDWARE;
|
||||||
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||||
|
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
|
||||||
//#ifdef _DEBUG
|
D3D11_SDK_VERSION, d3d_device.put(), nullptr, nullptr);
|
||||||
// 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);
|
|
||||||
|
|
||||||
if (DXGI_ERROR_UNSUPPORTED == hr) {
|
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);
|
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::com_ptr<::IInspectable> d3d11_device;
|
||||||
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(
|
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(
|
||||||
dxgi_device.get(), d3d11_device.put()));
|
d3d_device.as<IDXGIDevice>().get(), d3d11_device.put()));
|
||||||
return d3d11_device
|
return d3d11_device
|
||||||
.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
|
.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<
|
auto activation_factory = winrt::get_activation_factory<
|
||||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
||||||
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
||||||
@@ -181,7 +173,7 @@ auto wgc_session_impl::create_capture_item(HWND hwnd) {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto wgc_session_impl::create_capture_item(HMONITOR hmonitor) {
|
auto WgcSessionImpl::CreateCaptureItemForMonitor(HMONITOR hmonitor) {
|
||||||
auto activation_factory = winrt::get_activation_factory<
|
auto activation_factory = winrt::get_activation_factory<
|
||||||
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
||||||
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
||||||
@@ -193,10 +185,9 @@ auto wgc_session_impl::create_capture_item(HMONITOR hmonitor) {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT wgc_session_impl::create_mapped_texture(
|
HRESULT WgcSessionImpl::CreateMappedTexture(
|
||||||
winrt::com_ptr<ID3D11Texture2D> src_texture, unsigned int width,
|
winrt::com_ptr<ID3D11Texture2D> src_texture, unsigned int width,
|
||||||
unsigned int height) {
|
unsigned int height) {
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC src_desc;
|
D3D11_TEXTURE2D_DESC src_desc;
|
||||||
src_texture->GetDesc(&src_desc);
|
src_texture->GetDesc(&src_desc);
|
||||||
D3D11_TEXTURE2D_DESC map_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.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||||
map_desc.MiscFlags = 0;
|
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,
|
return d3dDevice->CreateTexture2D(&map_desc, nullptr,
|
||||||
d3d11_texture_mapped_.put());
|
d3d11_texture_mapped_.put());
|
||||||
}
|
}
|
||||||
|
|
||||||
void wgc_session_impl::on_frame(
|
void WgcSessionImpl::OnFrame(
|
||||||
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const &sender,
|
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const &sender,
|
||||||
winrt::Windows::Foundation::IInspectable const &args) {
|
winrt::Windows::Foundation::IInspectable const &args) {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
@@ -240,10 +232,10 @@ void wgc_session_impl::on_frame(
|
|||||||
// copy to mapped texture
|
// copy to mapped texture
|
||||||
{
|
{
|
||||||
auto frame_captured =
|
auto frame_captured =
|
||||||
get_dxgi_interface<ID3D11Texture2D>(frame.Surface());
|
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
|
||||||
|
|
||||||
if (!d3d11_texture_mapped_ || is_new_size)
|
if (!d3d11_texture_mapped_ || is_new_size)
|
||||||
create_mapped_texture(frame_captured);
|
CreateMappedTexture(frame_captured);
|
||||||
|
|
||||||
d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(),
|
d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(),
|
||||||
frame_captured.get());
|
frame_captured.get());
|
||||||
@@ -262,61 +254,12 @@ void wgc_session_impl::on_frame(
|
|||||||
|
|
||||||
// copy data from map_result.pData
|
// copy data from map_result.pData
|
||||||
if (map_result.pData && observer_) {
|
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.Width),
|
||||||
static_cast<unsigned int>(frame_size.Height), map_result.RowPitch,
|
static_cast<unsigned int>(frame_size.Height), map_result.RowPitch,
|
||||||
const_cast<const unsigned char *>(
|
const_cast<const unsigned char *>(
|
||||||
(unsigned char *)map_result.pData)});
|
(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);
|
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::Graphics::Capture::GraphicsCaptureItem const &,
|
||||||
winrt::Windows::Foundation::IInspectable const &) {
|
winrt::Windows::Foundation::IInspectable const &) {
|
||||||
OutputDebugStringW(L"wgc_session_impl::on_closed");
|
OutputDebugStringW(L"WgcSessionImpl::OnClosed");
|
||||||
}
|
}
|
||||||
|
|
||||||
int wgc_session_impl::initialize() {
|
int WgcSessionImpl::Initialize() {
|
||||||
if (is_initialized_)
|
if (is_initialized_) return 0;
|
||||||
return AM_ERROR::AE_NO;
|
|
||||||
|
|
||||||
if (!(d3d11_direct_device_ = create_d3d11_device()))
|
if (!(d3d11_direct_device_ = CreateD3D11Device())) {
|
||||||
return AM_ERROR::AE_D3D_CREATE_DEVICE_FAILED;
|
std::cout << "AE_D3D_CREATE_DEVICE_FAILED" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (target_.is_window)
|
if (target_.is_window)
|
||||||
capture_item_ = create_capture_item(target_.hwnd);
|
capture_item_ = CreateCaptureItemForWindow(target_.hwnd);
|
||||||
else
|
else
|
||||||
capture_item_ = create_capture_item(target_.hmonitor);
|
capture_item_ = CreateCaptureItemForMonitor(target_.hmonitor);
|
||||||
|
|
||||||
// Set up
|
// 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());
|
d3d11_device->GetImmediateContext(d3d11_device_context_.put());
|
||||||
|
|
||||||
} catch (winrt::hresult_error) {
|
} catch (winrt::hresult_error) {
|
||||||
return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
|
||||||
|
return 86;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return AM_ERROR::AE_WGC_CREATE_CAPTURER_FAILED;
|
return 86;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_initialized_ = true;
|
is_initialized_ = true;
|
||||||
|
|
||||||
return AM_ERROR::AE_NO;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wgc_session_impl::cleanup() {
|
void WgcSessionImpl::CleanUp() {
|
||||||
std::lock_guard locker(lock_);
|
std::lock_guard locker(lock_);
|
||||||
|
|
||||||
auto expected = false;
|
auto expected = false;
|
||||||
@@ -372,11 +318,9 @@ void wgc_session_impl::cleanup() {
|
|||||||
capture_close_trigger_.revoke();
|
capture_close_trigger_.revoke();
|
||||||
capture_framepool_trigger_.revoke();
|
capture_framepool_trigger_.revoke();
|
||||||
|
|
||||||
if (capture_framepool_)
|
if (capture_framepool_) capture_framepool_.Close();
|
||||||
capture_framepool_.Close();
|
|
||||||
|
|
||||||
if (capture_session_)
|
if (capture_session_) capture_session_.Close();
|
||||||
capture_session_.Close();
|
|
||||||
|
|
||||||
capture_framepool_ = nullptr;
|
capture_framepool_ = nullptr;
|
||||||
capture_session_ = 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);
|
return DefWindowProc(window, message, w_param, l_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wgc_session_impl::message_func() {
|
// void WgcSessionImpl::message_func() {
|
||||||
const std::wstring kClassName = L"am_fake_window";
|
// const std::wstring kClassName = L"am_fake_window";
|
||||||
|
|
||||||
WNDCLASS wc = {};
|
// WNDCLASS wc = {};
|
||||||
|
|
||||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
// wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||||
wc.lpfnWndProc = DefWindowProc;
|
// wc.lpfnWndProc = DefWindowProc;
|
||||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
// wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||||
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
|
// wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
|
||||||
wc.lpszClassName = kClassName.c_str();
|
// wc.lpszClassName = kClassName.c_str();
|
||||||
|
|
||||||
if (!::RegisterClassW(&wc))
|
// if (!::RegisterClassW(&wc)) return;
|
||||||
return;
|
|
||||||
|
|
||||||
hwnd_ = ::CreateWindowW(kClassName.c_str(), nullptr, WS_OVERLAPPEDWINDOW, 0,
|
// hwnd_ = ::CreateWindowW(kClassName.c_str(), nullptr, WS_OVERLAPPEDWINDOW,
|
||||||
0, 0, 0, nullptr, nullptr, nullptr, nullptr);
|
// 0,
|
||||||
MSG msg;
|
// 0, 0, 0, nullptr, nullptr, nullptr, nullptr);
|
||||||
while (is_running_) {
|
// MSG msg;
|
||||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
// while (is_running_) {
|
||||||
if (!is_running_)
|
// while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
break;
|
// if (!is_running_) break;
|
||||||
TranslateMessage(&msg);
|
// TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
// DispatchMessage(&msg);
|
||||||
}
|
// }
|
||||||
Sleep(10);
|
// Sleep(10);
|
||||||
}
|
// }
|
||||||
|
|
||||||
::CloseWindow(hwnd_);
|
// ::CloseWindow(hwnd_);
|
||||||
::DestroyWindow(hwnd_);
|
// ::DestroyWindow(hwnd_);
|
||||||
}
|
// }
|
||||||
|
|
||||||
} // namespace am
|
|
||||||
@@ -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 <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace am {
|
#include "wgc_session.h"
|
||||||
class wgc_session_impl : public wgc_session {
|
|
||||||
|
class WgcSessionImpl : public WgcSession {
|
||||||
struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
|
struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
|
||||||
IDirect3DDxgiInterfaceAccess : ::IUnknown {
|
IDirect3DDxgiInterfaceAccess : ::IUnknown {
|
||||||
virtual HRESULT __stdcall GetInterface(GUID const &id, void **object) = 0;
|
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 {
|
struct {
|
||||||
union {
|
union {
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
@@ -19,44 +35,41 @@ class wgc_session_impl : public wgc_session {
|
|||||||
} target_{0};
|
} target_{0};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wgc_session_impl();
|
WgcSessionImpl();
|
||||||
~wgc_session_impl() override;
|
~WgcSessionImpl() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void release() override;
|
void Release() override;
|
||||||
|
|
||||||
int initialize(HWND hwnd) override;
|
int Initialize(HWND hwnd) override;
|
||||||
int initialize(HMONITOR hmonitor) 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 Start() override;
|
||||||
int stop() override;
|
int Stop() override;
|
||||||
|
|
||||||
int pause() override;
|
int Pause() override;
|
||||||
int resume() override;
|
int Resume() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto create_d3d11_device();
|
auto CreateD3D11Device();
|
||||||
auto create_capture_item(HWND hwnd);
|
auto CreateCaptureItemForWindow(HWND hwnd);
|
||||||
auto create_capture_item(HMONITOR hmonitor);
|
auto CreateCaptureItemForMonitor(HMONITOR hmonitor);
|
||||||
template <typename T>
|
|
||||||
auto
|
HRESULT CreateMappedTexture(winrt::com_ptr<ID3D11Texture2D> src_texture,
|
||||||
get_dxgi_interface(winrt::Windows::Foundation::IInspectable const &object);
|
unsigned int width = 0, unsigned int height = 0);
|
||||||
HRESULT create_mapped_texture(winrt::com_ptr<ID3D11Texture2D> src_texture,
|
void OnFrame(
|
||||||
unsigned int width = 0,
|
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const
|
||||||
unsigned int height = 0);
|
|
||||||
void
|
|
||||||
on_frame(winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const
|
|
||||||
&sender,
|
&sender,
|
||||||
winrt::Windows::Foundation::IInspectable const &args);
|
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 &);
|
winrt::Windows::Foundation::IInspectable const &);
|
||||||
|
|
||||||
int initialize();
|
int Initialize();
|
||||||
void cleanup();
|
void CleanUp();
|
||||||
|
|
||||||
void message_func();
|
// void message_func();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex lock_;
|
std::mutex lock_;
|
||||||
@@ -90,15 +103,14 @@ private:
|
|||||||
HWND hwnd_ = nullptr;
|
HWND hwnd_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
// template <typename T>
|
||||||
inline auto wgc_session_impl::get_dxgi_interface(
|
// inline auto WgcSessionImpl::GetDXGIInterfaceFromObject(
|
||||||
winrt::Windows::Foundation::IInspectable const &object) {
|
// winrt::Windows::Foundation::IInspectable const &object) {
|
||||||
auto access = object.as<IDirect3DDxgiInterfaceAccess>();
|
// auto access = object.as<IDirect3DDxgiInterfaceAccess>();
|
||||||
winrt::com_ptr<T> result;
|
// winrt::com_ptr<T> result;
|
||||||
winrt::check_hresult(
|
// winrt::check_hresult(
|
||||||
access->GetInterface(winrt::guid_of<T>(), result.put_void()));
|
// access->GetInterface(winrt::guid_of<T>(), result.put_void()));
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
#endif
|
||||||
} // namespace am
|
|
||||||
@@ -11,9 +11,9 @@ add_requires("spdlog 1.11.0", "ffmpeg 5.1.2", {system = false})
|
|||||||
add_defines("UNICODE")
|
add_defines("UNICODE")
|
||||||
|
|
||||||
if is_os("windows") then
|
if is_os("windows") then
|
||||||
-- add_ldflags("/SUBSYSTEM:CONSOLE")
|
add_ldflags("/SUBSYSTEM:CONSOLE")
|
||||||
add_links("Shell32", "windowsapp", "dwmapi", "User32", "kernel32")
|
add_links("Shell32", "windowsapp", "dwmapi", "User32", "kernel32")
|
||||||
-- add_requires("vcpkg::sdl2")
|
add_requires("vcpkg::sdl2 2.26.4")
|
||||||
elseif is_os("linux") then
|
elseif is_os("linux") then
|
||||||
add_links("pthread")
|
add_links("pthread")
|
||||||
set_config("cxxflags", "-fPIC")
|
set_config("cxxflags", "-fPIC")
|
||||||
@@ -34,7 +34,11 @@ target("remote_desk")
|
|||||||
add_deps("projectx")
|
add_deps("projectx")
|
||||||
add_packages("log")
|
add_packages("log")
|
||||||
add_packages("ffmpeg")
|
add_packages("ffmpeg")
|
||||||
|
add_packages("vcpkg::sdl2")
|
||||||
add_links("avfilter", "avdevice", "avformat", "avcodec", "swscale", "swresample", "avutil")
|
add_links("avfilter", "avdevice", "avformat", "avcodec", "swscale", "swresample", "avutil")
|
||||||
add_files("dll/*.cpp")
|
add_files("dll/*.cpp")
|
||||||
add_includedirs("../../src/interface")
|
add_includedirs("../../src/interface")
|
||||||
-- add_links("SDL2main", "SDL2-static")
|
add_links("SDL2-static", "SDL2main", "Shell32", "gdi32", "winmm",
|
||||||
|
"setupapi", "version", "WindowsApp", "Imm32", "avutil")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user