Fix compile error

This commit is contained in:
dijunkun
2023-11-19 23:30:41 -08:00
parent 4a16857da8
commit e802306148
21 changed files with 349 additions and 127 deletions

127
src/log/log.h Normal file
View File

@@ -0,0 +1,127 @@
#ifndef _LOG_H_
#define _LOG_H_
#include <chrono>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include "spdlog/common.h"
#include "spdlog/logger.h"
#include "spdlog/sinks/base_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"
using namespace std::chrono;
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
// SPDLOG_TRACE(...)
// SPDLOG_DEBUG(...)
// SPDLOG_INFO(...)
// SPDLOG_WARN(...)
// SPDLOG_ERROR(...)
// SPDLOG_CRITICAL(...)
#ifdef SIGNAL_LOGGER
constexpr auto LOGGER_NAME = "siganl_server";
#else
constexpr auto LOGGER_NAME = "remote_desk";
#endif
#define LOG_INFO(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
combined_logger->flush_on(spdlog::level::info); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_INFO(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_INFO(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#define LOG_WARN(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_WARN(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_WARN(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#define LOG_ERROR(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_ERROR(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_ERROR(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#define LOG_FATAL(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_CRITICAL(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_CRITICAL(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#endif

View File

@@ -0,0 +1,309 @@
#include <stdio.h>
#define __STDC_CONSTANT_MACROS
#ifdef _WIN32
// Windows
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include "SDL2/SDL.h"
};
#else
// Linux...
#ifdef __cplusplus
extern "C" {
#endif
#include <SDL2/SDL.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
};
#endif
#endif
#include <chrono>
// Output YUV420P
#define OUTPUT_YUV420P 0
//'1' Use Dshow
//'0' Use GDIgrab
#define USE_DSHOW 0
// Refresh Event
#define SFM_REFRESH_EVENT (SDL_USEREVENT + 1)
#define SFM_BREAK_EVENT (SDL_USEREVENT + 2)
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
int thread_exit = 0;
SDL_Texture *sdlTexture = nullptr;
SDL_Renderer *sdlRenderer = nullptr;
SDL_Rect sdlRect;
unsigned char nv12_buffer[NV12_BUFFER_SIZE];
std::chrono::_V2::system_clock::time_point last_frame_time;
const int pixel_w = 1280, pixel_h = 720;
int screen_w = 1280, screen_h = 720;
bool done = false;
int YUV420ToNV12FFmpeg(unsigned char *src_buffer, int width, int height,
unsigned char *des_buffer) {
AVFrame *Input_pFrame = av_frame_alloc();
AVFrame *Output_pFrame = av_frame_alloc();
struct SwsContext *img_convert_ctx = sws_getContext(
width, height, AV_PIX_FMT_NV12, width, height, AV_PIX_FMT_YUV420P,
SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
av_image_fill_arrays(Input_pFrame->data, Input_pFrame->linesize, src_buffer,
AV_PIX_FMT_NV12, width, height, 1);
av_image_fill_arrays(Output_pFrame->data, Output_pFrame->linesize, des_buffer,
AV_PIX_FMT_YUV420P, width, height, 1);
sws_scale(img_convert_ctx, (uint8_t const **)Input_pFrame->data,
Input_pFrame->linesize, 0, height, Output_pFrame->data,
Output_pFrame->linesize);
if (Input_pFrame) av_free(Input_pFrame);
if (Output_pFrame) av_free(Output_pFrame);
if (img_convert_ctx) sws_freeContext(img_convert_ctx);
return 0;
}
int sfp_refresh_thread(void *opaque) {
thread_exit = 0;
while (!thread_exit) {
SDL_Event event;
event.type = SFM_REFRESH_EVENT;
SDL_PushEvent(&event);
SDL_Delay(30);
printf("sfp_refresh_thread\n");
}
thread_exit = 0;
// Break
SDL_Event event;
event.type = SFM_BREAK_EVENT;
SDL_PushEvent(&event);
printf("exit sfp_refresh_thread\n");
return 0;
}
int main(int argc, char *argv[]) {
AVFormatContext *pFormatCtx;
int i, videoindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVCodecParameters *pCodecParam;
// avformat_network_init();
pFormatCtx = avformat_alloc_context();
// Open File
char filepath[] = "out.h264";
// avformat_open_input(&pFormatCtx, filepath, NULL, NULL);
// Register Device
avdevice_register_all();
// Windows
// Linux
AVDictionary *options = NULL;
// Set some options
// grabbing frame rate
av_dict_set(&options, "framerate", "30", 0);
// Make the grabbed area follow the mouse
// av_dict_set(&options, "follow_mouse", "centered", 0);
// Video frame size. The default is to capture the full screen
av_dict_set(&options, "video_size", "1280x720", 0);
AVInputFormat *ifmt = (AVInputFormat *)av_find_input_format("x11grab");
if (!ifmt) {
printf("Couldn't find_input_format\n");
}
// Grab at position 10,20
if (avformat_open_input(&pFormatCtx, ":0.0", ifmt, &options) != 0) {
printf("Couldn't open input stream.\n");
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
printf("Couldn't find stream information.\n");
return -1;
}
videoindex = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++)
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoindex = i;
break;
}
if (videoindex == -1) {
printf("Didn't find a video stream.\n");
return -1;
}
pCodecParam = pFormatCtx->streams[videoindex]->codecpar;
pCodecCtx = avcodec_alloc_context3(NULL);
avcodec_parameters_to_context(pCodecCtx, pCodecParam);
pCodec = const_cast<AVCodec *>(avcodec_find_decoder(pCodecCtx->codec_id));
if (pCodec == NULL) {
printf("Codec not found.\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
printf("Could not open codec.\n");
return -1;
}
AVFrame *pFrame, *pFrameYUV, *pFrameNV12;
pFrame = av_frame_alloc();
pFrameYUV = av_frame_alloc();
pFrameNV12 = av_frame_alloc();
// unsigned char *out_buffer=(unsigned char
// *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width,
// pCodecCtx->height)); avpicture_fill((AVPicture *)pFrameYUV, out_buffer,
// AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
// SDL----------------------------
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
// const SDL_VideoInfo *vi = SDL_GetVideoInfo();
// Half of the Desktop's width and height.
screen_w = 1280;
screen_h = 720;
// SDL_Surface *screen;
// screen = SDL_SetVideoMode(screen_w, screen_h, 0, 0);
SDL_Window *screen;
screen = SDL_CreateWindow("Linux Capture", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h,
SDL_WINDOW_RESIZABLE);
if (!screen) {
printf("SDL: could not set video mode - exiting:%s\n", SDL_GetError());
return -1;
}
// SDL_Overlay *bmp;
// bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,
// SDL_YV12_OVERLAY, screen);
sdlRenderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED);
Uint32 pixformat = 0;
pixformat = SDL_PIXELFORMAT_NV12;
SDL_Texture *sdlTexture = nullptr;
sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat,
SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.w = screen_w;
rect.h = screen_h;
// SDL End------------------------
int ret, got_picture;
AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
struct SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(
pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width,
pCodecCtx->height, AV_PIX_FMT_NV12, SWS_BICUBIC, NULL, NULL, NULL);
//------------------------------
SDL_Thread *video_tid = SDL_CreateThread(sfp_refresh_thread, NULL, NULL);
//
// SDL_WM_SetCaption("Simplest FFmpeg Grab Desktop", NULL);
// Event Loop
SDL_Event event;
last_frame_time = std::chrono::high_resolution_clock::now();
for (;;) {
// Wait
SDL_WaitEvent(&event);
if (1) {
//------------------------------
if (av_read_frame(pFormatCtx, packet) >= 0) {
if (packet->stream_index == videoindex) {
avcodec_send_packet(pCodecCtx, packet);
av_packet_unref(packet);
got_picture = avcodec_receive_frame(pCodecCtx, pFrame);
// ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,
// packet);
if (ret < 0) {
printf("Decode Error.\n");
return -1;
}
printf("xxxxxxxxxxxxxxxxxxx\n");
if (!got_picture) {
auto now_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = now_time - last_frame_time;
auto tc = duration.count() * 1000;
printf("duration: %f\n", tc);
last_frame_time = now_time;
av_image_fill_arrays(pFrameNV12->data, pFrameNV12->linesize,
nv12_buffer, AV_PIX_FMT_NV12, pFrame->width,
pFrame->height, 1);
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0,
pFrame->height, pFrameNV12->data, pFrameNV12->linesize);
SDL_UpdateTexture(sdlTexture, NULL, nv12_buffer, pixel_w);
// FIX: If window is resize
sdlRect.x = 0;
sdlRect.y = 0;
sdlRect.w = screen_w;
sdlRect.h = screen_h;
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
SDL_RenderPresent(sdlRenderer);
}
}
// av_free_packet(packet);
} else {
// Exit Thread
// thread_exit = 1;
// printf("No frame read\n");
}
} else if (event.type == SDL_QUIT) {
printf("SDL_QUIT\n");
thread_exit = 1;
} else if (event.type == SFM_BREAK_EVENT) {
break;
}
}
sws_freeContext(img_convert_ctx);
#if OUTPUT_YUV420P
fclose(fp_yuv);
#endif
SDL_Quit();
// av_free(out_buffer);
av_frame_free(&pFrameNV12);
av_free(pFrameYUV);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
getchar();
return 0;
}

View File

@@ -0,0 +1,818 @@
#include <SDL.h>
#include <stdio.h>
#ifdef _WIN32
// #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#pragma comment(linker, "/subsystem:\"console\"")
#include <Winsock2.h>
#include <iphlpapi.h>
#elif __APPLE__
#include <ifaddrs.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <sys/socket.h>
#include <sys/types.h>
#elif __linux__
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include <chrono>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <thread>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavfilter/avfilter.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
};
#include "imgui.h"
#include "imgui_impl_sdl2.h"
#include "imgui_impl_sdlrenderer2.h"
#include "log.h"
#ifdef _WIN32
#include "screen_capture_wgc.h"
#elif __linux__
#include "screen_capture_x11.h"
#endif
#include "../../thirdparty/projectx/src/interface/x.h"
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
#ifdef REMOTE_DESK_DEBUG
#define MOUSE_CONTROL 0
#else
#define MOUSE_CONTROL 1
#endif
int screen_w = 1280, screen_h = 720;
int window_w = 1280, window_h = 720;
const int pixel_w = 1280, pixel_h = 720;
unsigned char dst_buffer[pixel_w * pixel_h * 3 / 2];
SDL_Texture *sdlTexture = nullptr;
SDL_Renderer *sdlRenderer = nullptr;
SDL_Rect sdlRect;
SDL_Window *window;
uint32_t start_time, end_time, elapsed_time;
uint32_t frame_count = 0;
int fps = 0;
std::string window_title = "Remote Desk Client";
std::string connection_status = "-";
// Refresh Event
#define REFRESH_EVENT (SDL_USEREVENT + 1)
#define QUIT_EVENT (SDL_USEREVENT + 2)
int thread_exit = 0;
PeerPtr *peer_server = nullptr;
PeerPtr *peer_client = nullptr;
bool joined = false;
bool received_frame = false;
static bool connect_button_pressed = false;
static const char *connect_label = "Connect";
#ifdef _WIN32
ScreenCaptureWgc *screen_capture = nullptr;
#elif __linux__
ScreenCaptureX11 *screen_capture = nullptr;
#endif
char *nv12_buffer = nullptr;
#ifdef __linux__
std::chrono::_V2::system_clock::time_point last_frame_time_;
#else
std::chrono::steady_clock::time_point last_frame_time_;
#endif
typedef enum { mouse = 0, keyboard } ControlType;
typedef enum { move = 0, left_down, left_up, right_down, right_up } MouseFlag;
typedef enum { key_down = 0, key_up } KeyFlag;
typedef struct {
size_t x;
size_t y;
MouseFlag flag;
} Mouse;
typedef struct {
size_t key_value;
KeyFlag flag;
} Key;
typedef struct {
ControlType type;
union {
Mouse m;
Key k;
};
} RemoteAction;
inline int ProcessMouseKeyEven(SDL_Event &ev) {
float ratio = 1280.0 / window_w;
RemoteAction remote_action;
if (SDL_KEYDOWN == ev.type) // SDL_KEYUP
{
// printf("SDLK_DOWN: %d\n", SDL_KeyCode(ev.key.keysym.sym));
if (SDLK_DOWN == ev.key.keysym.sym) {
// printf("SDLK_DOWN \n");
} else if (SDLK_UP == ev.key.keysym.sym) {
// printf("SDLK_UP \n");
} else if (SDLK_LEFT == ev.key.keysym.sym) {
// printf("SDLK_LEFT \n");
} else if (SDLK_RIGHT == ev.key.keysym.sym) {
// printf("SDLK_RIGHT \n");
}
} else if (SDL_MOUSEBUTTONDOWN == ev.type) {
if (SDL_BUTTON_LEFT == ev.button.button) {
int px = ev.button.x;
int py = ev.button.y;
// printf("SDL_MOUSEBUTTONDOWN x, y %d %d \n", px, py);
remote_action.type = ControlType::mouse;
remote_action.m.flag = MouseFlag::left_down;
remote_action.m.x = ev.button.x * ratio;
remote_action.m.y = ev.button.y * ratio;
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
sizeof(remote_action));
} else if (SDL_BUTTON_RIGHT == ev.button.button) {
int px = ev.button.x;
int py = ev.button.y;
// printf("SDL_BUTTON_RIGHT x, y %d %d \n", px, py);
remote_action.type = ControlType::mouse;
remote_action.m.flag = MouseFlag::right_down;
remote_action.m.x = ev.button.x * ratio;
remote_action.m.y = ev.button.y * ratio;
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
sizeof(remote_action));
}
} else if (SDL_MOUSEBUTTONUP == ev.type) {
if (SDL_BUTTON_LEFT == ev.button.button) {
int px = ev.button.x;
int py = ev.button.y;
// printf("SDL_MOUSEBUTTONUP x, y %d %d \n", px, py);
remote_action.type = ControlType::mouse;
remote_action.m.flag = MouseFlag::left_up;
remote_action.m.x = ev.button.x * ratio;
remote_action.m.y = ev.button.y * ratio;
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
sizeof(remote_action));
} else if (SDL_BUTTON_RIGHT == ev.button.button) {
int px = ev.button.x;
int py = ev.button.y;
// printf("SDL_MOUSEBUTTONUP x, y %d %d \n", px, py);
remote_action.type = ControlType::mouse;
remote_action.m.flag = MouseFlag::right_up;
remote_action.m.x = ev.button.x * ratio;
remote_action.m.y = ev.button.y * ratio;
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
sizeof(remote_action));
}
} else if (SDL_MOUSEMOTION == ev.type) {
int px = ev.motion.x;
int py = ev.motion.y;
// printf("SDL_MOUSEMOTION x, y %d %d \n", px, py);
remote_action.type = ControlType::mouse;
remote_action.m.flag = MouseFlag::move;
remote_action.m.x = ev.button.x * ratio;
remote_action.m.y = ev.button.y * ratio;
SendData(peer_client, DATA_TYPE::DATA, (const char *)&remote_action,
sizeof(remote_action));
} else if (SDL_QUIT == ev.type) {
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent(&event);
printf("SDL_QUIT\n");
return 0;
}
return 0;
}
void ReceiveVideoBuffer(const char *data, size_t size, const char *user_id,
size_t user_id_size) {
// std::cout << "Receive: [" << user_id << "] " << std::endl;
if (joined) {
memcpy(dst_buffer, data, size);
SDL_Event event;
event.type = REFRESH_EVENT;
SDL_PushEvent(&event);
received_frame = true;
}
}
void ReceiveAudioBuffer(const char *data, size_t size, const char *user_id,
size_t user_id_size) {
std::cout << "Receive audio, size " << size << ", user [" << user_id << "] "
<< std::endl;
}
void ReceiveDataBuffer(const char *data, size_t size, const char *user_id,
size_t user_id_size) {
std::string user(user_id, user_id_size);
RemoteAction remote_action;
memcpy(&remote_action, data, sizeof(remote_action));
// std::cout << "remote_action: " << remote_action.type << " "
// << remote_action.m.flag << " " << remote_action.m.x << " "
// << remote_action.m.y << std::endl;
#ifdef _WIN32
INPUT ip;
if (remote_action.type == ControlType::mouse) {
ip.type = INPUT_MOUSE;
ip.mi.dx = remote_action.m.x * screen_w / 1280;
ip.mi.dy = remote_action.m.y * screen_h / 720;
if (remote_action.m.flag == MouseFlag::left_down) {
ip.mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
} else if (remote_action.m.flag == MouseFlag::left_up) {
ip.mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
} else if (remote_action.m.flag == MouseFlag::right_down) {
ip.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE;
} else if (remote_action.m.flag == MouseFlag::right_up) {
ip.mi.dwFlags = MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE;
} else {
ip.mi.dwFlags = MOUSEEVENTF_MOVE;
}
ip.mi.mouseData = 0;
ip.mi.time = 0;
#if MOUSE_CONTROL
// Set cursor pos
SetCursorPos(ip.mi.dx, ip.mi.dy);
// Send the press
if (ip.mi.dwFlags != MOUSEEVENTF_MOVE) {
SendInput(1, &ip, sizeof(INPUT));
}
#endif
// std::cout << "Receive data from [" << user << "], " << ip.type << " "
// << ip.mi.dwFlags << " " << ip.mi.dx << " " << ip.mi.dy
// << std::endl;
}
#endif
}
void ConnectionStatus(ConnectionStatus status) {
if (ConnectionStatus::Connecting == status) {
connection_status = "Connecting";
} else if (ConnectionStatus::Connected == status) {
connection_status = "Connected";
} else if (ConnectionStatus::Failed == status) {
connection_status = "Failed";
} else if (ConnectionStatus::Closed == status) {
connection_status = "Closed";
} else if (ConnectionStatus::IncorrectPassword == status) {
connection_status = "Incorrect password";
if (connect_button_pressed) {
connect_button_pressed = false;
joined = false;
connect_label = connect_button_pressed ? "Disconnect" : "Connect";
}
}
}
std::string GetMac(char *mac_addr) {
int len = 0;
#ifdef _WIN32
IP_ADAPTER_INFO adapterInfo[16];
DWORD bufferSize = sizeof(adapterInfo);
DWORD result = GetAdaptersInfo(adapterInfo, &bufferSize);
if (result == ERROR_SUCCESS) {
PIP_ADAPTER_INFO adapter = adapterInfo;
while (adapter) {
for (UINT i = 0; i < adapter->AddressLength; i++) {
len += sprintf(mac_addr + len, "%.2X", adapter->Address[i]);
}
break;
}
}
#elif __APPLE__
std::string if_name = "en0";
struct ifaddrs *addrs;
struct ifaddrs *cursor;
const struct sockaddr_dl *dlAddr;
if (!getifaddrs(&addrs)) {
cursor = addrs;
while (cursor != 0) {
const struct sockaddr_dl *socAddr =
(const struct sockaddr_dl *)cursor->ifa_addr;
if ((cursor->ifa_addr->sa_family == AF_LINK) &&
(socAddr->sdl_type == IFT_ETHER) &&
strcmp(if_name.c_str(), cursor->ifa_name) == 0) {
dlAddr = (const struct sockaddr_dl *)cursor->ifa_addr;
const unsigned char *base =
(const unsigned char *)&dlAddr->sdl_data[dlAddr->sdl_nlen];
for (int i = 0; i < dlAddr->sdl_alen; i++) {
len += sprintf(mac_addr + len, "%.2X", base[i]);
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
#elif __linux__
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
return "";
}
struct ifreq ifr;
struct ifconf ifc;
char buf[1024];
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
close(sock);
return "";
}
struct ifreq *it = ifc.ifc_req;
const struct ifreq *const end = it + (ifc.ifc_len / sizeof(struct ifreq));
for (; it != end; ++it) {
std::strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
continue;
}
if (ifr.ifr_flags & IFF_LOOPBACK) {
continue;
}
if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
continue;
}
std::string mac_address;
for (int i = 0; i < 6; ++i) {
len += sprintf(mac_addr + len, "%.2X", ifr.ifr_hwaddr.sa_data[i] & 0xff);
}
break;
}
close(sock);
#endif
return mac_addr;
}
int BGRAToNV12FFmpeg(unsigned char *src_buffer, int width, int height,
unsigned char *dst_buffer) {
AVFrame *Input_pFrame = av_frame_alloc();
AVFrame *Output_pFrame = av_frame_alloc();
struct SwsContext *img_convert_ctx =
sws_getContext(width, height, AV_PIX_FMT_BGRA, 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_BGRA, width, height, 1);
av_image_fill_arrays(Output_pFrame->data, Output_pFrame->linesize, dst_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;
}
int main() {
LOG_INFO("Remote desk");
std::string default_cfg_path = "../../../../config/config.ini";
std::ifstream f(default_cfg_path.c_str());
Params params;
params.cfg_path = f.good() ? "../../../../config/config.ini" : "config.ini";
params.on_receive_video_buffer = ReceiveVideoBuffer;
params.on_receive_audio_buffer = ReceiveAudioBuffer;
params.on_receive_data_buffer = ReceiveDataBuffer;
params.on_connection_status = ConnectionStatus;
std::string transmission_id = "000001";
char mac_addr[10];
GetMac(mac_addr);
peer_server = CreatePeer(&params);
std::string server_user_id = "S-" + std::string(GetMac(mac_addr));
Init(peer_server, server_user_id.c_str());
peer_client = CreatePeer(&params);
std::string client_user_id = "C-" + std::string(GetMac(mac_addr));
Init(peer_client, client_user_id.c_str());
{
static char server_password[20] = "";
std::string user_id = "S-" + std::string(GetMac(mac_addr));
CreateConnection(peer_server, mac_addr, server_password);
nv12_buffer = new char[NV12_BUFFER_SIZE];
#ifdef _WIN32
screen_capture = new ScreenCaptureWgc();
RECORD_DESKTOP_RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = GetSystemMetrics(SM_CXSCREEN);
rect.bottom = GetSystemMetrics(SM_CYSCREEN);
last_frame_time_ = std::chrono::high_resolution_clock::now();
screen_capture->Init(
rect, 60,
[](unsigned char *data, int size, int width, int height) -> void {
auto now_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = now_time - last_frame_time_;
auto tc = duration.count() * 1000;
if (tc >= 0) {
BGRAToNV12FFmpeg(data, width, height, (unsigned char *)nv12_buffer);
SendData(peer_server, DATA_TYPE::VIDEO, (const char *)nv12_buffer,
NV12_BUFFER_SIZE);
// std::cout << "Send" << std::endl;
last_frame_time_ = now_time;
}
});
screen_capture->Start();
#elif __linux__
screen_capture = new ScreenCaptureX11();
RECORD_DESKTOP_RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = 0;
rect.bottom = 0;
last_frame_time_ = std::chrono::high_resolution_clock::now();
screen_capture->Init(
rect, 60,
[](unsigned char *data, int size, int width, int height) -> void {
auto now_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = now_time - last_frame_time_;
auto tc = duration.count() * 1000;
if (tc >= 0) {
SendData(peer_server, DATA_TYPE::VIDEO, (const char *)data,
NV12_BUFFER_SIZE);
last_frame_time_ = now_time;
}
});
screen_capture->Start();
#endif
}
// Setup SDL
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) !=
0) {
printf("Error: %s\n", SDL_GetError());
return -1;
}
// From 2.0.18: Enable native IME.
#ifdef SDL_HINT_IME_SHOW_UI
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif
// Create window with SDL_Renderer graphics context
SDL_WindowFlags window_flags =
(SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
window = SDL_CreateWindow("Remote Desk", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, window_w, window_h,
window_flags);
SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM);
screen_w = DM.w;
screen_h = DM.h;
sdlRenderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
if (sdlRenderer == nullptr) {
SDL_Log("Error creating SDL_Renderer!");
return 0;
}
Uint32 pixformat = 0;
pixformat = SDL_PIXELFORMAT_NV12;
sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat,
SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO();
io.ConfigFlags |=
ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |=
ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
// ImGui::StyleColorsLight();
// Setup Platform/Renderer backends
ImGui_ImplSDL2_InitForSDLRenderer(window, sdlRenderer);
ImGui_ImplSDLRenderer2_Init(sdlRenderer);
// Our state
bool show_demo_window = true;
bool show_another_window = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Main loop
bool done = false;
while (!done) {
// Start the Dear ImGui frame
ImGui_ImplSDLRenderer2_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
{
static float f = 0.0f;
static int counter = 0;
const ImGuiViewport *main_viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(180, 130));
ImGui::Begin("Menu", nullptr, ImGuiWindowFlags_NoResize);
{
// ImGui::Text("LOCAL ID: ");
// ImGui::SameLine();
// ImGui::Selectable(mac_addr, false,
// ImGuiSelectableFlags_AllowDoubleClick);
// if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) {
// ImGui::SetClipboardText(mac_addr);
// }
// ImGui::Spacing();
// ImGui::Text("PASSWORD: ");
// ImGui::SameLine();
// ImGui::SetNextItemWidth(110);
// static char server_password[20] = "";
// ImGui::InputTextWithHint("server_password", "000001",
// server_password,
// IM_ARRAYSIZE(server_password),
// ImGuiInputTextFlags_AllowTabInput);
// ImGui::Spacing();
// {
// static bool online_button_pressed = false;
// static const char *online_label = "Online";
// if (ImGui::Button(online_label)) {
// std::string user_id = "S-" +
// std::string(GetMac(mac_addr));
// if (strcmp(online_label, "Online") == 0) {
// CreateConnection(peer_server, mac_addr,
// server_password);
// nv12_buffer = new char[NV12_BUFFER_SIZE];
// #ifdef _WIN32
// screen_capture = new ScreenCaptureWgc();
// RECORD_DESKTOP_RECT rect;
// rect.left = 0;
// rect.top = 0;
// rect.right = GetSystemMetrics(SM_CXSCREEN);
// rect.bottom = GetSystemMetrics(SM_CYSCREEN);
// last_frame_time_ =
// std::chrono::high_resolution_clock::now();
// screen_capture->Init(
// rect, 60,
// [](unsigned char *data, int size, int width,
// int height) -> void {
// auto now_time =
// std::chrono::high_resolution_clock::now();
// std::chrono::duration<double> duration =
// now_time - last_frame_time_;
// auto tc = duration.count() * 1000;
// if (tc >= 0) {
// BGRAToNV12FFmpeg(data, width, height,
// (unsigned char *)nv12_buffer);
// SendData(peer_server, DATA_TYPE::VIDEO,
// (const char *)nv12_buffer,
// NV12_BUFFER_SIZE);
// // std::cout << "Send" << std::endl;
// last_frame_time_ = now_time;
// }
// });
// screen_capture->Start();
// #elif __linux__
// screen_capture = new ScreenCaptureX11();
// RECORD_DESKTOP_RECT rect;
// rect.left = 0;
// rect.top = 0;
// rect.right = 0;
// rect.bottom = 0;
// last_frame_time_ =
// std::chrono::high_resolution_clock::now();
// screen_capture->Init(
// rect, 60,
// [](unsigned char *data, int size, int width,
// int height) -> void {
// auto now_time =
// std::chrono::high_resolution_clock::now();
// std::chrono::duration<double> duration =
// now_time - last_frame_time_;
// auto tc = duration.count() * 1000;
// if (tc >= 0) {
// SendData(peer_server, DATA_TYPE::VIDEO,
// (const char *)data, NV12_BUFFER_SIZE);
// last_frame_time_ = now_time;
// }
// });
// screen_capture->Start();
// #endif
// } else {
// LeaveConnection(peer_server);
// }
// online_button_pressed = !online_button_pressed;
// online_label = online_button_pressed ? "Offline" :
// "Online";
// }
// }
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
{
{
static char remote_id[20] = "";
if (strcmp(remote_id, "") == 0) {
strcpy(remote_id, GetMac(mac_addr).c_str());
}
ImGui::Text("REMOTE ID:");
ImGui::SameLine();
ImGui::SetNextItemWidth(110);
ImGui::InputTextWithHint("id_buf", "000002", remote_id,
IM_ARRAYSIZE(remote_id),
ImGuiInputTextFlags_AllowTabInput);
ImGui::Spacing();
// ImGui::Text("PASSWORD: ");
// ImGui::SameLine();
// ImGui::SetNextItemWidth(110);
static char client_password[20] = "";
// ImGui::InputTextWithHint("client_password", "000003",
// client_password,
// IM_ARRAYSIZE(client_password),
// ImGuiInputTextFlags_AllowTabInput);
if (ImGui::Button(connect_label)) {
if (strcmp(connect_label, "Connect") == 0 && !joined) {
std::string user_id = "C-" + std::string(GetMac(mac_addr));
JoinConnection(peer_client, remote_id, client_password);
joined = true;
} else if (strcmp(connect_label, "Disconnect") == 0 && joined) {
LeaveConnection(peer_client);
joined = false;
received_frame = false;
}
connect_button_pressed = !connect_button_pressed;
connect_label = connect_button_pressed ? "Disconnect" : "Connect";
}
}
}
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
{
if (ImGui::Button("Fix ratio")) {
SDL_GetWindowSize(window, &window_w, &window_h);
if (window_h != window_w * 9 / 16) {
window_w = window_h * 16 / 9;
}
SDL_SetWindowSize(window, window_w, window_h);
}
}
ImGui::End();
}
// Rendering
ImGui::Render();
SDL_RenderSetScale(sdlRenderer, io.DisplayFramebufferScale.x,
io.DisplayFramebufferScale.y);
SDL_Event event;
while (SDL_PollEvent(&event)) {
ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT) {
done = true;
} else if (event.type == SDL_WINDOWEVENT &&
event.window.event == SDL_WINDOWEVENT_RESIZED) {
SDL_GetWindowSize(window, &window_w, &window_h);
SDL_SetWindowSize(window, window_w, window_h);
// printf("Resize windows: %dx%d\n", window_w, window_h);
} else if (event.type == SDL_WINDOWEVENT &&
event.window.event == SDL_WINDOWEVENT_CLOSE &&
event.window.windowID == SDL_GetWindowID(window)) {
done = true;
} else if (event.type == REFRESH_EVENT) {
sdlRect.x = 0;
sdlRect.y = 0;
sdlRect.w = window_w;
sdlRect.h = window_h;
SDL_UpdateTexture(sdlTexture, NULL, dst_buffer, pixel_w);
} else {
if (joined) {
ProcessMouseKeyEven(event);
}
}
}
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
if (!joined || !received_frame) {
SDL_RenderClear(sdlRenderer);
SDL_SetRenderDrawColor(
sdlRenderer, (Uint8)(clear_color.x * 0), (Uint8)(clear_color.y * 0),
(Uint8)(clear_color.z * 0), (Uint8)(clear_color.w * 0));
}
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData());
SDL_RenderPresent(sdlRenderer);
frame_count++;
end_time = SDL_GetTicks();
elapsed_time = end_time - start_time;
if (elapsed_time >= 1000) {
fps = frame_count / (elapsed_time / 1000);
frame_count = 0;
window_title = "Remote Desk Client FPS [" + std::to_string(fps) +
"] status [" + connection_status + "]";
// For MacOS, UI frameworks can only be called from the main thread
SDL_SetWindowTitle(window, window_title.c_str());
start_time = end_time;
}
}
// Cleanup
LeaveConnection(peer_server);
ImGui_ImplSDLRenderer2_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
SDL_DestroyRenderer(sdlRenderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

View File

@@ -0,0 +1,131 @@
#include "screen_capture_x11.h"
#include <iostream>
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
unsigned char nv12_buffer_[NV12_BUFFER_SIZE];
ScreenCaptureX11::ScreenCaptureX11() {}
ScreenCaptureX11::~ScreenCaptureX11() {
if (capture_thread_->joinable()) {
capture_thread_->join();
}
}
int ScreenCaptureX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
cb_desktop_data cb) {
if (cb) {
_on_data = cb;
}
pFormatCtx_ = avformat_alloc_context();
avdevice_register_all();
// grabbing frame rate
av_dict_set(&options_, "framerate", "30", 0);
// Make the grabbed area follow the mouse
av_dict_set(&options_, "follow_mouse", "centered", 0);
// Video frame size. The default is to capture the full screen
av_dict_set(&options_, "video_size", "1280x720", 0);
ifmt_ = (AVInputFormat *)av_find_input_format("x11grab");
if (!ifmt_) {
printf("Couldn't find_input_format\n");
}
// Grab at position 10,20
if (avformat_open_input(&pFormatCtx_, ":0.0", ifmt_, &options_) != 0) {
printf("Couldn't open input stream.\n");
return -1;
}
if (avformat_find_stream_info(pFormatCtx_, NULL) < 0) {
printf("Couldn't find stream information.\n");
return -1;
}
videoindex_ = -1;
for (i_ = 0; i_ < pFormatCtx_->nb_streams; i_++)
if (pFormatCtx_->streams[i_]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoindex_ = i_;
break;
}
if (videoindex_ == -1) {
printf("Didn't find a video stream.\n");
return -1;
}
pCodecParam_ = pFormatCtx_->streams[videoindex_]->codecpar;
pCodecCtx_ = avcodec_alloc_context3(NULL);
avcodec_parameters_to_context(pCodecCtx_, pCodecParam_);
pCodec_ = const_cast<AVCodec *>(avcodec_find_decoder(pCodecCtx_->codec_id));
if (pCodec_ == NULL) {
printf("Codec not found.\n");
return -1;
}
if (avcodec_open2(pCodecCtx_, pCodec_, NULL) < 0) {
printf("Could not open codec.\n");
return -1;
}
pFrame_ = av_frame_alloc();
pFrameNv12_ = av_frame_alloc();
const int pixel_w = 1280, pixel_h = 720;
int screen_w = 1280, screen_h = 720;
screen_w = 1280;
screen_h = 720;
packet_ = (AVPacket *)av_malloc(sizeof(AVPacket));
img_convert_ctx_ =
sws_getContext(pCodecCtx_->width, pCodecCtx_->height, pCodecCtx_->pix_fmt,
pCodecCtx_->width, pCodecCtx_->height, AV_PIX_FMT_NV12,
SWS_BICUBIC, NULL, NULL, NULL);
return 0;
}
int ScreenCaptureX11::Start() {
capture_thread_.reset(new std::thread([this]() {
while (1) {
if (av_read_frame(pFormatCtx_, packet_) >= 0) {
if (packet_->stream_index == videoindex_) {
avcodec_send_packet(pCodecCtx_, packet_);
av_packet_unref(packet_);
got_picture_ = avcodec_receive_frame(pCodecCtx_, pFrame_);
if (!got_picture_) {
av_image_fill_arrays(pFrameNv12_->data, pFrameNv12_->linesize,
nv12_buffer_, AV_PIX_FMT_NV12, pFrame_->width,
pFrame_->height, 1);
sws_scale(img_convert_ctx_, pFrame_->data, pFrame_->linesize, 0,
pFrame_->height, pFrameNv12_->data,
pFrameNv12_->linesize);
_on_data((unsigned char *)nv12_buffer_,
pFrame_->width * pFrame_->height * 3 / 2, pFrame_->width,
pFrame_->height);
}
}
}
}
}));
return 0;
}
int ScreenCaptureX11::Pause() { return 0; }
int ScreenCaptureX11::Resume() { return 0; }
int ScreenCaptureX11::Stop() { return 0; }
void ScreenCaptureX11::OnFrame() {}
void ScreenCaptureX11::CleanUp() {}

View File

@@ -0,0 +1,85 @@
#ifndef _SCREEN_CAPTURE_X11_H_
#define _SCREEN_CAPTURE_X11_H_
#include <atomic>
#include <functional>
#include <string>
#include <thread>
#ifdef __cplusplus
extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
};
#endif
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 ScreenCaptureX11 {
public:
ScreenCaptureX11();
~ScreenCaptureX11();
public:
int Init(const RECORD_DESKTOP_RECT &rect, const int fps, cb_desktop_data cb);
int Start();
int Pause();
int Resume();
int Stop();
void OnFrame();
protected:
void CleanUp();
private:
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;
private:
int i_ = 0;
int videoindex_ = 0;
int got_picture_ = 0;
// ffmpeg
AVFormatContext *pFormatCtx_ = nullptr;
AVCodecContext *pCodecCtx_ = nullptr;
AVCodec *pCodec_ = nullptr;
AVCodecParameters *pCodecParam_ = nullptr;
AVDictionary *options_ = nullptr;
AVInputFormat *ifmt_ = nullptr;
AVFrame *pFrame_ = nullptr;
AVFrame *pFrameNv12_ = nullptr;
AVPacket *packet_ = nullptr;
struct SwsContext *img_convert_ctx_ = nullptr;
// thread
std::unique_ptr<std::thread> capture_thread_ = nullptr;
};
#endif

View File

@@ -0,0 +1,37 @@
#ifndef _X11_SESSION_H_
#define _X11_SESSION_H_
class X11Session {
public:
struct x11_session_frame {
unsigned int width;
unsigned int height;
unsigned int row_pitch;
const unsigned char *data;
};
class x11_session_observer {
public:
virtual ~x11_session_observer() {}
virtual void OnFrame(const x11_session_frame &frame) = 0;
};
public:
virtual void Release() = 0;
virtual int Initialize() = 0;
virtual void RegisterObserver(x11_session_observer *observer) = 0;
virtual int Start() = 0;
virtual int Stop() = 0;
virtual int Pause() = 0;
virtual int Resume() = 0;
protected:
virtual ~X11Session(){};
};
#endif

View File

@@ -0,0 +1,49 @@
#include "x11_session_impl.h"
#include <atomic>
#include <functional>
#include <iostream>
#include <memory>
#define CHECK_INIT \
if (!is_initialized_) { \
std::cout << "AE_NEED_INIT" << std::endl; \
return 4; \
}
X11SessionImpl::X11SessionImpl() {}
X11SessionImpl::~X11SessionImpl() {
Stop();
CleanUp();
}
void X11SessionImpl::Release() { delete this; }
int X11SessionImpl::Initialize() { return 0; }
void X11SessionImpl::RegisterObserver(x11_session_observer *observer) {
observer_ = observer;
}
int X11SessionImpl::Start() {
if (is_running_) return 0;
int error = 1;
CHECK_INIT;
return error;
}
int X11SessionImpl::Stop() { return 0; }
int X11SessionImpl::Pause() { return 0; }
int X11SessionImpl::Resume() { return 0; }
void X11SessionImpl::OnFrame() {}
void X11SessionImpl::OnClosed() {}
void X11SessionImpl::CleanUp() {}

View File

@@ -0,0 +1,44 @@
#ifndef _WGC_SESSION_IMPL_H_
#define _WGC_SESSION_IMPL_H_
#include <mutex>
#include <thread>
#include "x11_session.h"
class X11SessionImpl : public X11Session {
public:
X11SessionImpl();
~X11SessionImpl() override;
public:
void Release() override;
int Initialize() override;
void RegisterObserver(x11_session_observer *observer) override;
int Start() override;
int Stop() override;
int Pause() override;
int Resume() override;
private:
void OnFrame();
void OnClosed();
void CleanUp();
// void message_func();
private:
std::mutex lock_;
bool is_initialized_ = false;
bool is_running_ = false;
bool is_paused_ = false;
x11_session_observer *observer_ = nullptr;
};
#endif

View File

@@ -0,0 +1,26 @@
#include "screen_capture_wgc.h"
#include <iostream>
ScreenCaptureWgc::ScreenCaptureWgc() {}
ScreenCaptureWgc::~ScreenCaptureWgc() {}
bool ScreenCaptureWgc::IsWgcSupported() { return false; }
int ScreenCaptureWgc::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
cb_desktop_data cb) {
return 0;
}
int ScreenCaptureWgc::Start() { return 0; }
int ScreenCaptureWgc::Pause() { return 0; }
int ScreenCaptureWgc::Resume() { return 0; }
int ScreenCaptureWgc::Stop() { return 0; }
void ScreenCaptureWgc::OnFrame() {}
void ScreenCaptureWgc::CleanUp() {}

View File

@@ -0,0 +1,56 @@
#ifndef _SCREEN_CAPTURE_WGC_H_
#define _SCREEN_CAPTURE_WGC_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:
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();
protected:
void CleanUp();
private:
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;
};
#endif

View File

@@ -0,0 +1,138 @@
#include "screen_capture_wgc.h"
#include <Windows.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;
_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) {
if (_on_data)
_on_data((unsigned char *)frame.data, frame.width * frame.height * 4,
frame.width, frame.height);
}
void ScreenCaptureWgc::CleanUp() {
_inited = false;
if (session_) session_->Release();
session_ = nullptr;
}

View File

@@ -0,0 +1,61 @@
#ifndef _SCREEN_CAPTURE_WGC_H_
#define _SCREEN_CAPTURE_WGC_H_
#include <atomic>
#include <functional>
#include <string>
#include <thread>
#include "wgc_session.h"
#include "wgc_session_impl.h"
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;
};
#endif

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

@@ -0,0 +1,366 @@
#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_) { \
std::cout << "AE_NEED_INIT" << std::endl; \
return 4; \
}
#define CHECK_CLOSED \
if (cleaned_.load() == true) { \
throw winrt::hresult_error(RO_E_CLOSED); \
}
extern "C" {
HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(
::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice);
}
WgcSessionImpl::WgcSessionImpl() {}
WgcSessionImpl::~WgcSessionImpl() {
Stop();
CleanUp();
}
void WgcSessionImpl::Release() { delete this; }
int WgcSessionImpl::Initialize(HWND hwnd) {
std::lock_guard locker(lock_);
target_.hwnd = hwnd;
target_.is_window = true;
return Initialize();
}
int WgcSessionImpl::Initialize(HMONITOR hmonitor) {
std::lock_guard locker(lock_);
target_.hmonitor = hmonitor;
target_.is_window = false;
return Initialize();
}
void WgcSessionImpl::RegisterObserver(wgc_session_observer *observer) {
std::lock_guard locker(lock_);
observer_ = observer;
}
int WgcSessionImpl::Start() {
std::lock_guard locker(lock_);
if (is_running_) return 0;
int error = 1;
CHECK_INIT;
try {
if (!capture_session_) {
auto current_size = capture_item_.Size();
capture_framepool_ =
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
CreateFreeThreaded(d3d11_direct_device_,
winrt::Windows::Graphics::DirectX::
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2, current_size);
capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
capture_frame_size_ = current_size;
capture_framepool_trigger_ = capture_framepool_.FrameArrived(
winrt::auto_revoke, {this, &WgcSessionImpl::OnFrame});
capture_close_trigger_ = capture_item_.Closed(
winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed});
}
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(&WgcSessionImpl::message_func, this));
capture_session_.StartCapture();
error = 0;
} catch (winrt::hresult_error) {
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
return 86;
} catch (...) {
return 86;
}
return error;
}
int WgcSessionImpl::Stop() {
std::lock_guard locker(lock_);
CHECK_INIT;
is_running_ = false;
// if (loop_.joinable()) loop_.join();
if (capture_framepool_trigger_) capture_framepool_trigger_.revoke();
if (capture_session_) {
capture_session_.Close();
capture_session_ = nullptr;
}
return 0;
}
int WgcSessionImpl::Pause() {
std::lock_guard locker(lock_);
CHECK_INIT;
return 0;
}
int WgcSessionImpl::Resume() {
std::lock_guard locker(lock_);
CHECK_INIT;
return 0;
}
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;
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
D3D11_SDK_VERSION, d3d_device.put(), nullptr, nullptr);
if (DXGI_ERROR_UNSUPPORTED == hr) {
// change D3D_DRIVER_TYPE
D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_WARP;
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
D3D11_SDK_VERSION, d3d_device.put(), nullptr,
nullptr);
}
winrt::check_hresult(hr);
winrt::com_ptr<::IInspectable> d3d11_device;
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(
d3d_device.as<IDXGIDevice>().get(), d3d11_device.put()));
return d3d11_device
.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
}
auto WgcSessionImpl::CreateCaptureItemForWindow(HWND hwnd) {
auto activation_factory = winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
interop_factory->CreateForWindow(
hwnd,
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
reinterpret_cast<void **>(winrt::put_abi(item)));
return item;
}
auto WgcSessionImpl::CreateCaptureItemForMonitor(HMONITOR hmonitor) {
auto activation_factory = winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
interop_factory->CreateForMonitor(
hmonitor,
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
reinterpret_cast<void **>(winrt::put_abi(item)));
return item;
}
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;
map_desc.Width = width == 0 ? src_desc.Width : width;
map_desc.Height = height == 0 ? src_desc.Height : height;
map_desc.MipLevels = src_desc.MipLevels;
map_desc.ArraySize = src_desc.ArraySize;
map_desc.Format = src_desc.Format;
map_desc.SampleDesc = src_desc.SampleDesc;
map_desc.Usage = D3D11_USAGE_STAGING;
map_desc.BindFlags = 0;
map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
map_desc.MiscFlags = 0;
auto d3dDevice =
GetDXGIInterfaceFromObject<ID3D11Device>(d3d11_direct_device_);
return d3dDevice->CreateTexture2D(&map_desc, nullptr,
d3d11_texture_mapped_.put());
}
void WgcSessionImpl::OnFrame(
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const &sender,
winrt::Windows::Foundation::IInspectable const &args) {
std::lock_guard locker(lock_);
auto is_new_size = false;
{
auto frame = sender.TryGetNextFrame();
auto frame_size = frame.ContentSize();
if (frame_size.Width != capture_frame_size_.Width ||
frame_size.Height != capture_frame_size_.Height) {
// The thing we have been capturing has changed size.
// We need to resize our swap chain first, then blit the pixels.
// After we do that, retire the frame and then recreate our frame pool.
is_new_size = true;
capture_frame_size_ = frame_size;
}
// copy to mapped texture
{
auto frame_captured =
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
if (!d3d11_texture_mapped_ || is_new_size)
CreateMappedTexture(frame_captured);
d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(),
frame_captured.get());
D3D11_MAPPED_SUBRESOURCE map_result;
HRESULT hr = d3d11_device_context_->Map(
d3d11_texture_mapped_.get(), 0, D3D11_MAP_READ,
0 /*coz we use CreateFreeThreaded, so we cant use flags
D3D11_MAP_FLAG_DO_NOT_WAIT*/
,
&map_result);
if (FAILED(hr)) {
OutputDebugStringW(
(L"map resource failed: " + std::to_wstring(hr)).c_str());
}
// copy data from map_result.pData
if (map_result.pData && observer_) {
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)});
}
d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0);
}
}
if (is_new_size) {
capture_framepool_.Recreate(d3d11_direct_device_,
winrt::Windows::Graphics::DirectX::
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2, capture_frame_size_);
}
}
void WgcSessionImpl::OnClosed(
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
winrt::Windows::Foundation::IInspectable const &) {
OutputDebugStringW(L"WgcSessionImpl::OnClosed");
}
int WgcSessionImpl::Initialize() {
if (is_initialized_) return 0;
if (!(d3d11_direct_device_ = CreateD3D11Device())) {
std::cout << "AE_D3D_CREATE_DEVICE_FAILED" << std::endl;
return 1;
}
try {
if (target_.is_window)
capture_item_ = CreateCaptureItemForWindow(target_.hwnd);
else
capture_item_ = CreateCaptureItemForMonitor(target_.hmonitor);
// Set up
auto d3d11_device =
GetDXGIInterfaceFromObject<ID3D11Device>(d3d11_direct_device_);
d3d11_device->GetImmediateContext(d3d11_device_context_.put());
} catch (winrt::hresult_error) {
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
return 86;
} catch (...) {
return 86;
}
is_initialized_ = true;
return 0;
}
void WgcSessionImpl::CleanUp() {
std::lock_guard locker(lock_);
auto expected = false;
if (cleaned_.compare_exchange_strong(expected, true)) {
capture_close_trigger_.revoke();
capture_framepool_trigger_.revoke();
if (capture_framepool_) capture_framepool_.Close();
if (capture_session_) capture_session_.Close();
capture_framepool_ = nullptr;
capture_session_ = nullptr;
capture_item_ = nullptr;
is_initialized_ = false;
}
}
LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param,
LPARAM l_param) {
return DefWindowProc(window, message, w_param, l_param);
}
// void WgcSessionImpl::message_func() {
// const std::wstring kClassName = L"am_fake_window";
// 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();
// 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);
// }
// ::CloseWindow(hwnd_);
// ::DestroyWindow(hwnd_);
// }

View File

@@ -0,0 +1,116 @@
#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>
#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;
HMONITOR hmonitor;
};
bool is_window;
} target_{0};
public:
WgcSessionImpl();
~WgcSessionImpl() override;
public:
void Release() override;
int Initialize(HWND hwnd) override;
int Initialize(HMONITOR hmonitor) override;
void RegisterObserver(wgc_session_observer *observer) override;
int Start() override;
int Stop() override;
int Pause() override;
int Resume() override;
private:
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 OnClosed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
winrt::Windows::Foundation::IInspectable const &);
int Initialize();
void CleanUp();
// void message_func();
private:
std::mutex lock_;
bool is_initialized_ = false;
bool is_running_ = false;
bool is_paused_ = false;
wgc_session_observer *observer_ = nullptr;
// wgc
winrt::Windows::Graphics::Capture::GraphicsCaptureItem capture_item_{nullptr};
winrt::Windows::Graphics::Capture::GraphicsCaptureSession capture_session_{
nullptr};
winrt::Windows::Graphics::SizeInt32 capture_frame_size_;
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice
d3d11_direct_device_{nullptr};
winrt::com_ptr<ID3D11DeviceContext> d3d11_device_context_{nullptr};
winrt::com_ptr<ID3D11Texture2D> d3d11_texture_mapped_{nullptr};
std::atomic<bool> cleaned_ = false;
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool
capture_framepool_{nullptr};
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
FrameArrived_revoker capture_framepool_trigger_;
winrt::Windows::Graphics::Capture::GraphicsCaptureItem::Closed_revoker
capture_close_trigger_;
// message loop
std::thread loop_;
HWND hwnd_ = nullptr;
};
// 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;
// }
#endif