mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35:34 +08:00
Split applications from this project
This commit is contained in:
@@ -1,309 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,818 +0,0 @@
|
||||
#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 "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(¶ms);
|
||||
std::string server_user_id = "S-" + std::string(GetMac(mac_addr));
|
||||
Init(peer_server, server_user_id.c_str());
|
||||
|
||||
peer_client = CreatePeer(¶ms);
|
||||
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;
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
#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() {}
|
||||
@@ -1,85 +0,0 @@
|
||||
#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
|
||||
@@ -1,37 +0,0 @@
|
||||
#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
|
||||
@@ -1,49 +0,0 @@
|
||||
#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() {}
|
||||
@@ -1,44 +0,0 @@
|
||||
#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
|
||||
@@ -1,26 +0,0 @@
|
||||
#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() {}
|
||||
@@ -1,56 +0,0 @@
|
||||
#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
|
||||
@@ -1,138 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#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
|
||||
@@ -1,40 +0,0 @@
|
||||
#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,366 +0,0 @@
|
||||
#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_);
|
||||
// }
|
||||
@@ -1,116 +0,0 @@
|
||||
#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
|
||||
206
application/remote_desk/thirdparty/ffmpeg/xmake.lua
vendored
206
application/remote_desk/thirdparty/ffmpeg/xmake.lua
vendored
@@ -1,206 +0,0 @@
|
||||
package("ffmpeg")
|
||||
|
||||
set_homepage("https://www.ffmpeg.org")
|
||||
set_description("A collection of libraries to process multimedia content such as audio, video, subtitles and related metadata.")
|
||||
set_license("GPL-3.0")
|
||||
|
||||
if is_plat("windows", "mingw") then
|
||||
add_urls("https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-$(version)-full_build-shared.7z")
|
||||
add_versions("5.1.2", "d9eb97b72d7cfdae4d0f7eaea59ccffb8c364d67d88018ea715d5e2e193f00e9")
|
||||
add_versions("5.0.1", "ded28435b6f04b74f5ef5a6a13761233bce9e8e9f8ecb0eabe936fd36a778b0c")
|
||||
|
||||
add_configs("shared", {description = "Download shared binaries.", default = true, type = "boolean", readonly = true})
|
||||
add_configs("vs_runtime", {description = "Set vs compiler runtime.", default = "MD", readonly = true})
|
||||
else
|
||||
add_urls("https://ffmpeg.org/releases/ffmpeg-$(version).tar.bz2", {alias = "home"})
|
||||
add_urls("https://github.com/FFmpeg/FFmpeg/archive/n$(version).zip", {alias = "github"})
|
||||
add_urls("https://git.ffmpeg.org/ffmpeg.git", "https://github.com/FFmpeg/FFmpeg.git", {alias = "git"})
|
||||
add_versions("home:5.1.2", "39a0bcc8d98549f16c570624678246a6ac736c066cebdb409f9502e915b22f2b")
|
||||
add_versions("home:5.1.1", "cd0e16f903421266d5ccddedf7b83b9e5754aef4b9f7a7f06ce9e4c802f0545b")
|
||||
add_versions("home:5.0.1", "28df33d400a1c1c1b20d07a99197809a3b88ef765f5f07dc1ff067fac64c59d6")
|
||||
add_versions("home:4.0.2", "346c51735f42c37e0712e0b3d2f6476c86ac15863e4445d9e823fe396420d056")
|
||||
add_versions("github:5.1.2", "0c99f3609160f40946e2531804175eea16416320c4b6365ad075e390600539db")
|
||||
add_versions("github:5.1.1", "a886fcc94792764c27c88ebe71dffbe5f0d37df8f06f01efac4833ac080c11bf")
|
||||
add_versions("github:5.0.1", "f9c2e06cafa4381df8d5c9c9e14d85d9afcbc10c516c6a206f821997cc7f6440")
|
||||
add_versions("github:4.0.2", "4df1ef0bf73b7148caea1270539ef7bd06607e0ea8aa2fbf1bb34062a097f026")
|
||||
add_versions("git:5.1.2", "n5.1.2")
|
||||
add_versions("git:5.1.1", "n5.1.1")
|
||||
add_versions("git:5.0.1", "n5.0.1")
|
||||
add_versions("git:4.0.2", "n4.0.2")
|
||||
|
||||
add_configs("gpl", {description = "Enable GPL code", default = false, type = "boolean"})
|
||||
add_configs("ffprobe", {description = "Enable ffprobe program.", default = false, type = "boolean"})
|
||||
add_configs("ffmpeg", {description = "Enable ffmpeg program.", default = true, type = "boolean"})
|
||||
add_configs("ffplay", {description = "Enable ffplay program.", default = false, type = "boolean"})
|
||||
add_configs("zlib", {description = "Enable zlib compression library.", default = false, type = "boolean"})
|
||||
add_configs("lzma", {description = "Enable liblzma compression library.", default = false, type = "boolean"})
|
||||
add_configs("bzlib", {description = "Enable bzlib compression library.", default = false, type = "boolean"})
|
||||
add_configs("libx264", {description = "Enable libx264 decoder.", default = false, type = "boolean"})
|
||||
add_configs("libx265", {description = "Enable libx265 decoder.", default = false, type = "boolean"})
|
||||
add_configs("iconv", {description = "Enable libiconv library.", default = false, type = "boolean"})
|
||||
add_configs("vaapi", {description = "Enable vaapi library.", default = false, type = "boolean"})
|
||||
add_configs("vdpau", {description = "Enable vdpau library.", default = false, type = "boolean"})
|
||||
add_configs("hardcoded-tables", {description = "Enable hardcoded tables.", default = true, type = "boolean"})
|
||||
add_configs("asm", {description = "Enable asm", default = false, type = "boolean"})
|
||||
add_configs("libopenh264", {description = "Enable libopenh264", default = true, type = "boolean"})
|
||||
end
|
||||
|
||||
add_links("avfilter", "avdevice", "avformat", "avcodec", "swscale", "swresample", "avutil")
|
||||
if is_plat("macosx") then
|
||||
add_frameworks("CoreFoundation", "Foundation", "CoreVideo", "CoreMedia", "AudioToolbox", "VideoToolbox", "Security")
|
||||
elseif is_plat("linux") then
|
||||
add_syslinks("pthread", "openh264")
|
||||
end
|
||||
|
||||
if is_plat("linux", "macosx") then
|
||||
add_deps("yasm")
|
||||
end
|
||||
|
||||
if on_fetch then
|
||||
on_fetch("mingw", "linux", "macosx", function (package, opt)
|
||||
import("lib.detect.find_tool")
|
||||
if opt.system then
|
||||
local result
|
||||
for _, name in ipairs({"libavcodec", "libavdevice", "libavfilter", "libavformat", "libavutil", "libpostproc", "libswresample", "libswscale"}) do
|
||||
local pkginfo = package:find_package("pkgconfig::" .. name, opt)
|
||||
if pkginfo then
|
||||
pkginfo.version = nil
|
||||
if not result then
|
||||
result = pkginfo
|
||||
else
|
||||
result = result .. pkginfo
|
||||
end
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
local ffmpeg = find_tool("ffmpeg", {check = "-help", version = true, command = "-version", parse = "%d+%.?%d+%.?%d+", force = true})
|
||||
if ffmpeg then
|
||||
result.version = ffmpeg.version
|
||||
end
|
||||
return result
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
on_load("linux", "macosx", "android", function (package)
|
||||
local configdeps = {zlib = "zlib",
|
||||
bzlib = "bzip2",
|
||||
lzma = "xz",
|
||||
libx264 = "x264",
|
||||
libx265 = "x265",
|
||||
iconv = "libiconv"}
|
||||
for name, dep in pairs(configdeps) do
|
||||
if package:config(name) then
|
||||
package:add("deps", dep)
|
||||
end
|
||||
end
|
||||
-- https://www.ffmpeg.org/platform.html#toc-Advanced-linking-configuration
|
||||
if package:config("pic") ~= false and not package:is_plat("macosx") then
|
||||
package:add("shflags", "-Wl,-Bsymbolic")
|
||||
package:add("ldflags", "-Wl,-Bsymbolic")
|
||||
end
|
||||
if not package:config("gpl") then
|
||||
package:set("license", "LGPL-3.0")
|
||||
end
|
||||
end)
|
||||
|
||||
on_install("windows|x64", "mingw|x86_64", function (package)
|
||||
os.cp("bin", package:installdir())
|
||||
os.cp("include", package:installdir())
|
||||
os.cp("lib", package:installdir())
|
||||
package:addenv("PATH", "bin")
|
||||
end)
|
||||
|
||||
on_install("linux", "macosx", "android@linux,macosx", function (package)
|
||||
local configs = {"--enable-version3",
|
||||
"--disable-doc"}
|
||||
if package:config("gpl") then
|
||||
table.insert(configs, "--enable-gpl")
|
||||
end
|
||||
if package:is_plat("macosx") and macos.version():ge("10.8") then
|
||||
table.insert(configs, "--enable-videotoolbox")
|
||||
end
|
||||
for name, enabled in pairs(package:configs()) do
|
||||
if not package:extraconf("configs", name, "builtin") then
|
||||
if enabled then
|
||||
table.insert(configs, "--enable-" .. name)
|
||||
else
|
||||
table.insert(configs, "--disable-" .. name)
|
||||
end
|
||||
end
|
||||
end
|
||||
if package:config("shared") then
|
||||
table.insert(configs, "--enable-shared")
|
||||
table.insert(configs, "--disable-static")
|
||||
else
|
||||
table.insert(configs, "--enable-static")
|
||||
table.insert(configs, "--disable-shared")
|
||||
end
|
||||
if package:debug() then
|
||||
table.insert(configs, "--enable-debug")
|
||||
else
|
||||
table.insert(configs, "--disable-debug")
|
||||
end
|
||||
if package:is_plat("android") then
|
||||
import("core.base.option")
|
||||
import("core.tool.toolchain")
|
||||
local ndk = toolchain.load("ndk", {plat = package:plat(), arch = package:arch()})
|
||||
local bin = ndk:bindir()
|
||||
local ndk_sdkver = ndk:config("ndk_sdkver")
|
||||
local arch, cpu, triple, cross_prefix
|
||||
if package:is_arch("arm64-v8a") then
|
||||
arch = "arm64"
|
||||
cpu = "armv8-a"
|
||||
triple = "aarch64-linux-android"
|
||||
cross_prefix = path.join(bin, "aarch64-linux-android-")
|
||||
elseif package:arch():startswith("arm") then
|
||||
arch = "arm"
|
||||
cpu = "armv7-a"
|
||||
triple = "armv7a-linux-androideabi"
|
||||
cross_prefix = path.join(bin, "arm-linux-androideabi-")
|
||||
else
|
||||
raise("unknown arch(%s) for android!", package:arch())
|
||||
end
|
||||
local sysroot = path.join(path.directory(bin), "sysroot")
|
||||
local cflags = table.join(table.wrap(package:config("cxflags")), table.wrap(package:config("cflags")), table.wrap(get_config("cxflags")), get_config("cflags"))
|
||||
local cxxflags = table.join(table.wrap(package:config("cxflags")), table.wrap(package:config("cxxflags")), table.wrap(get_config("cxflags")), get_config("cxxflags"))
|
||||
assert(os.isdir(sysroot), "we do not support old version ndk!")
|
||||
if package:is_arch("arm64-v8a") then
|
||||
table.insert(cflags, "-mfpu=neon")
|
||||
table.insert(cflags, "-mfloat-abi=soft")
|
||||
else
|
||||
table.insert(cflags, "-mfpu=neon")
|
||||
table.insert(cflags, "-mfloat-abi=soft")
|
||||
end
|
||||
table.insert(configs, "--enable-neon")
|
||||
table.insert(configs, "--enable-asm")
|
||||
table.insert(configs, "--enable-jni")
|
||||
table.insert(configs, "--target-os=android")
|
||||
table.insert(configs, "--enable-cross-compile")
|
||||
table.insert(configs, "--disable-avdevice")
|
||||
table.insert(configs, "--arch=" .. arch)
|
||||
table.insert(configs, "--cpu=" .. cpu)
|
||||
table.insert(configs, "--cc=" .. path.join(bin, triple .. ndk_sdkver .. "-clang"))
|
||||
table.insert(configs, "--cxx=" .. path.join(bin, triple .. ndk_sdkver .. "-clang++"))
|
||||
table.insert(configs, "--extra-cflags=" .. table.concat(cflags, ' '))
|
||||
table.insert(configs, "--extra-cxxflags=" .. table.concat(cxxflags, ' '))
|
||||
table.insert(configs, "--sysroot=" .. sysroot)
|
||||
table.insert(configs, "--cross-prefix=" .. cross_prefix)
|
||||
table.insert(configs, "--prefix=" .. package:installdir())
|
||||
os.vrunv("./configure", configs)
|
||||
local argv = {"-j4"}
|
||||
if option.get("verbose") then
|
||||
table.insert(argv, "V=1")
|
||||
end
|
||||
os.vrunv("make", argv)
|
||||
os.vrun("make install")
|
||||
else
|
||||
import("package.tools.autoconf").install(package, configs)
|
||||
end
|
||||
package:addenv("PATH", "bin")
|
||||
end)
|
||||
|
||||
on_test(function (package)
|
||||
assert(package:has_cfuncs("avformat_open_input", {includes = "libavformat/avformat.h"}))
|
||||
end)
|
||||
@@ -1,11 +0,0 @@
|
||||
package("sdl2")
|
||||
add_urls("https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.28.3.tar.gz", {alias = "github"})
|
||||
add_versions("github:2.28.3", "c17455d6e0c484bfe634b8de6af4c608e86ee449c28e40af04064aa6643fe382")
|
||||
|
||||
add_deps("cmake")
|
||||
on_install(function (package)
|
||||
local configs = {}
|
||||
table.insert(configs, "-DSDL_SHARED_ENABLED_BY_DEFAULT=OFF -DSDL_TEST_ENABLED_BY_DEFAULT=OFF")
|
||||
import("package.tools.cmake").install(package, configs)
|
||||
end)
|
||||
package_end()
|
||||
5
application/remote_desk/thirdparty/xmake.lua
vendored
5
application/remote_desk/thirdparty/xmake.lua
vendored
@@ -1,5 +0,0 @@
|
||||
includes("sdl2")
|
||||
if is_plat("windows") then
|
||||
elseif is_plat("linux") then
|
||||
includes("ffmpeg")
|
||||
end
|
||||
@@ -1,87 +0,0 @@
|
||||
set_project("remote_desk")
|
||||
set_version("0.0.1")
|
||||
set_license("LGPL-3.0")
|
||||
|
||||
add_rules("mode.release", "mode.debug")
|
||||
set_languages("c++17")
|
||||
|
||||
add_requires("spdlog 1.11.0", {system = false})
|
||||
add_requires("imgui 1.89.9", {configs = {sdl2 = true, sdl2_renderer = true}})
|
||||
add_defines("UNICODE")
|
||||
|
||||
add_requires("sdl2", {system = false})
|
||||
|
||||
if is_os("windows") then
|
||||
add_links("Shell32", "windowsapp", "dwmapi", "User32", "kernel32")
|
||||
add_requires("vcpkg::ffmpeg 5.1.2", {configs = {shared = false}})
|
||||
elseif is_os("linux") then
|
||||
add_requires("ffmpeg 5.1.2", {system = false})
|
||||
add_syslinks("pthread", "dl")
|
||||
elseif is_os("macosx") then
|
||||
add_requires("ffmpeg 5.1.2", {system = false})
|
||||
end
|
||||
|
||||
if is_mode("debug") then
|
||||
add_defines("REMOTE_DESK_DEBUG")
|
||||
end
|
||||
|
||||
add_packages("spdlog")
|
||||
|
||||
includes("thirdparty")
|
||||
|
||||
target("log")
|
||||
set_kind("headeronly")
|
||||
add_packages("spdlog")
|
||||
add_headerfiles("../utils/log/log.h")
|
||||
add_includedirs("../utils/log", {public = true})
|
||||
|
||||
target("screen_capture")
|
||||
set_kind("static")
|
||||
add_packages("log", "ffmpeg")
|
||||
if is_os("windows") then
|
||||
add_files("screen_capture/windows/*.cpp")
|
||||
add_includedirs("screen_capture/windows", {public = true})
|
||||
elseif is_os("macosx") then
|
||||
add_files("screen_capture/macosx/*.cpp")
|
||||
add_includedirs("screen_capture/macosx", {public = true})
|
||||
elseif is_os("linux") then
|
||||
add_files("screen_capture/linux/*.cpp")
|
||||
add_includedirs("screen_capture/linux", {public = true})
|
||||
end
|
||||
|
||||
target("remote_desk")
|
||||
set_kind("binary")
|
||||
add_deps("projectx", "screen_capture")
|
||||
add_packages("log", "sdl2", "imgui", "ffmpeg")
|
||||
add_files("remote_desk_gui/main.cpp")
|
||||
add_includedirs("../../src/interface")
|
||||
if is_os("windows") then
|
||||
add_links("SDL2-static", "SDL2main", "gdi32", "winmm",
|
||||
"setupapi", "version", "Imm32", "iphlpapi")
|
||||
elseif is_os("macosx") then
|
||||
add_links("SDL2")
|
||||
elseif is_os("linux") then
|
||||
add_links("SDL2")
|
||||
add_ldflags("-lavformat", "-lavdevice", "-lavfilter", "-lavcodec",
|
||||
"-lswscale", "-lavutil", "-lswresample",
|
||||
"-lasound", "-lxcb-shape", "-lxcb-xfixes", "-lsndio", "-lxcb",
|
||||
"-lxcb-shm", "-lXext", "-lX11", "-lXv", "-ldl", "-lpthread",
|
||||
{force = true})
|
||||
end
|
||||
after_install(function (target)
|
||||
os.cp("$(projectdir)/thirdparty/nvcodec/Lib/x64/*.so", "$(projectdir)/out/bin")
|
||||
os.cp("$(projectdir)/thirdparty/nvcodec/Lib/x64/*.so.1", "$(projectdir)/out/bin")
|
||||
os.cp("$(projectdir)/out/lib/*.so", "$(projectdir)/out/bin")
|
||||
os.rm("$(projectdir)/out/include")
|
||||
os.rm("$(projectdir)/out/lib")
|
||||
end)
|
||||
|
||||
-- target("linux_capture")
|
||||
-- set_kind("binary")
|
||||
-- add_packages("sdl2", "imgui", "ffmpeg", "openh264")
|
||||
-- add_files("remote_desk_gui/linux_capture.cpp")
|
||||
-- add_ldflags("-lavformat", "-lavdevice", "-lavfilter", "-lavcodec",
|
||||
-- "-lswscale", "-lavutil", "-lswresample",
|
||||
-- "-lasound", "-lxcb-shape", "-lxcb-xfixes", "-lsndio", "-lxcb",
|
||||
-- "-lxcb-shm", "-lXext", "-lX11", "-lXv", "-lpthread", "-lSDL2", "-lopenh264",
|
||||
-- "-ldl" ,{force = true})
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "signal_server.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
SignalServer s;
|
||||
std::string port = "";
|
||||
if (argc > 1) {
|
||||
port = argv[1];
|
||||
} else {
|
||||
port = "9090";
|
||||
}
|
||||
|
||||
s.run(std::stoi(port));
|
||||
return 0;
|
||||
}
|
||||
@@ -1,297 +0,0 @@
|
||||
#include "signal_server.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
|
||||
const std::string GenerateTransmissionId() {
|
||||
static const char alphanum[] = "0123456789";
|
||||
std::string random_id;
|
||||
random_id.reserve(6);
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
random_id += alphanum[rand() % (sizeof(alphanum) - 1)];
|
||||
}
|
||||
|
||||
return "000000";
|
||||
}
|
||||
|
||||
SignalServer::SignalServer() {
|
||||
// Set logging settings
|
||||
server_.set_error_channels(websocketpp::log::elevel::all);
|
||||
server_.set_access_channels(websocketpp::log::alevel::none);
|
||||
|
||||
// Initialize Asio
|
||||
server_.init_asio();
|
||||
|
||||
server_.set_open_handler(
|
||||
std::bind(&SignalServer::on_open, this, std::placeholders::_1));
|
||||
|
||||
server_.set_close_handler(
|
||||
std::bind(&SignalServer::on_close, this, std::placeholders::_1));
|
||||
|
||||
server_.set_message_handler(std::bind(&SignalServer::on_message, this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
|
||||
server_.set_ping_handler(bind(&SignalServer::on_ping, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
server_.set_pong_handler(bind(&SignalServer::on_pong, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
SignalServer::~SignalServer() {}
|
||||
|
||||
bool SignalServer::on_open(websocketpp::connection_hdl hdl) {
|
||||
ws_connections_[hdl] = ws_connection_id_++;
|
||||
LOG_INFO("New websocket connection [{}] established", ws_connection_id_);
|
||||
|
||||
json message = {{"type", "ws_connection_id"},
|
||||
{"ws_connection_id", ws_connection_id_}};
|
||||
server_.send(hdl, message.dump(), websocketpp::frame::opcode::text);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SignalServer::on_close(websocketpp::connection_hdl hdl) {
|
||||
LOG_INFO("Websocket onnection [{}] closed", ws_connection_id_);
|
||||
std::string user_id = transmission_manager_.GetUserId(hdl);
|
||||
std::string transmission_id =
|
||||
transmission_manager_.ReleaseUserIdFromTransmission(hdl);
|
||||
|
||||
if (!transmission_id.empty()) {
|
||||
json message = {{"type", "user_leave_transmission"},
|
||||
{"transmission_id", transmission_id},
|
||||
{"user_id", user_id}};
|
||||
|
||||
std::vector<std::string> user_id_list =
|
||||
transmission_manager_.GetAllUserIdOfTransmission(transmission_id);
|
||||
|
||||
if (user_id_list.empty()) {
|
||||
transmission_list_.erase(transmission_id);
|
||||
LOG_INFO("Release transmission [{}] due to no user in this transmission",
|
||||
transmission_id);
|
||||
}
|
||||
|
||||
if (std::string::npos != user_id.find("S-")) {
|
||||
transmission_list_.erase(transmission_id);
|
||||
transmission_manager_.ReleaseAllUserIdFromTransmission(transmission_id);
|
||||
LOG_INFO("Release transmission [{}] due to server leaves",
|
||||
transmission_id);
|
||||
}
|
||||
|
||||
for (const auto& user_id : user_id_list) {
|
||||
send_msg(transmission_manager_.GetWsHandle(user_id), message);
|
||||
}
|
||||
}
|
||||
ws_connections_.erase(hdl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SignalServer::on_ping(websocketpp::connection_hdl hdl, std::string s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SignalServer::on_pong(websocketpp::connection_hdl hdl, std::string s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SignalServer::run(uint16_t port) {
|
||||
LOG_INFO("Signal server runs on port [{}]", port);
|
||||
|
||||
server_.set_reuse_addr(true);
|
||||
server_.listen(port);
|
||||
|
||||
// Queues a connection accept operation
|
||||
server_.start_accept();
|
||||
|
||||
// Start the Asio io_service run loop
|
||||
server_.run();
|
||||
}
|
||||
|
||||
void SignalServer::send_msg(websocketpp::connection_hdl hdl, json message) {
|
||||
if (!hdl.expired()) {
|
||||
server_.send(hdl, message.dump(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
}
|
||||
|
||||
void SignalServer::on_message(websocketpp::connection_hdl hdl,
|
||||
server::message_ptr msg) {
|
||||
std::string payload = msg->get_payload();
|
||||
|
||||
auto j = json::parse(payload);
|
||||
std::string type = j["type"].get<std::string>();
|
||||
|
||||
switch (HASH_STRING_PIECE(type.c_str())) {
|
||||
case "create_transmission"_H: {
|
||||
std::string transmission_id = j["transmission_id"].get<std::string>();
|
||||
std::string password = j["password"].get<std::string>();
|
||||
std::string user_id = j["user_id"].get<std::string>();
|
||||
LOG_INFO("Receive user id [{}] create transmission request with id [{}]",
|
||||
user_id, transmission_id);
|
||||
if (transmission_list_.find(transmission_id) ==
|
||||
transmission_list_.end()) {
|
||||
if (transmission_id.empty()) {
|
||||
transmission_id = GenerateTransmissionId();
|
||||
while (transmission_list_.find(transmission_id) !=
|
||||
transmission_list_.end()) {
|
||||
transmission_id = GenerateTransmissionId();
|
||||
}
|
||||
LOG_INFO(
|
||||
"Transmission id is empty, generate a new one for this request "
|
||||
"[{}]",
|
||||
transmission_id);
|
||||
}
|
||||
transmission_list_.insert(transmission_id);
|
||||
|
||||
transmission_manager_.BindUserIdToTransmission(user_id,
|
||||
transmission_id);
|
||||
transmission_manager_.BindUserIdToWsHandle(user_id, hdl);
|
||||
transmission_manager_.BindPasswordToTransmission(password,
|
||||
transmission_id);
|
||||
|
||||
LOG_INFO("Create transmission id [{}]", transmission_id);
|
||||
json message = {{"type", "transmission_id"},
|
||||
{"transmission_id", transmission_id},
|
||||
{"status", "success"}};
|
||||
send_msg(hdl, message);
|
||||
} else {
|
||||
LOG_INFO("Transmission id [{}] already exist", transmission_id);
|
||||
json message = {{"type", "transmission_id"},
|
||||
{"transmission_id", transmission_id},
|
||||
{"status", "fail"},
|
||||
{"reason", "Transmission id exist"}};
|
||||
send_msg(hdl, message);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "leave_transmission"_H: {
|
||||
std::string transmission_id = j["transmission_id"].get<std::string>();
|
||||
std::string user_id = j["user_id"].get<std::string>();
|
||||
LOG_INFO("[{}] leaves transmission [{}]", user_id.c_str(),
|
||||
transmission_id.c_str());
|
||||
|
||||
json message = {{"type", "user_leave_transmission"},
|
||||
{"transmission_id", transmission_id},
|
||||
{"user_id", user_id}};
|
||||
|
||||
std::vector<std::string> user_id_list =
|
||||
transmission_manager_.GetAllUserIdOfTransmission(transmission_id);
|
||||
|
||||
for (const auto& user_id : user_id_list) {
|
||||
send_msg(transmission_manager_.GetWsHandle(user_id), message);
|
||||
}
|
||||
|
||||
transmission_manager_.ReleaseUserIdFromTransmission(hdl);
|
||||
if (std::string::npos != user_id.find("S-")) {
|
||||
transmission_list_.erase(transmission_id);
|
||||
transmission_manager_.ReleaseAllUserIdFromTransmission(transmission_id);
|
||||
LOG_INFO("Release transmission [{}] due to server leaves",
|
||||
transmission_id);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "query_user_id_list"_H: {
|
||||
std::string transmission_id = j["transmission_id"].get<std::string>();
|
||||
std::string password = j["password"].get<std::string>();
|
||||
|
||||
if (transmission_manager_.CheckPassword(password, transmission_id)) {
|
||||
std::vector<std::string> user_id_list =
|
||||
transmission_manager_.GetAllUserIdOfTransmission(transmission_id);
|
||||
|
||||
json message = {{"type", "user_id_list"},
|
||||
{"transmission_id", transmission_id},
|
||||
{"user_id_list", user_id_list},
|
||||
{"status", "success"}};
|
||||
|
||||
send_msg(hdl, message);
|
||||
} else {
|
||||
std::vector<std::string> user_id_list;
|
||||
json message = {{"type", "user_id_list"},
|
||||
{"transmission_id", transmission_id},
|
||||
{"user_id_list", user_id_list},
|
||||
{"status", "failed"},
|
||||
{"reason", "Incorrect password"}};
|
||||
// LOG_INFO(
|
||||
// "Incorrect password [{}] for transmission [{}] with password is "
|
||||
// "[{}]",
|
||||
// password, transmission_id,
|
||||
// transmission_manager_.GetPassword(transmission_id));
|
||||
|
||||
send_msg(hdl, message);
|
||||
}
|
||||
|
||||
// LOG_INFO("Send member_list: [{}]", message.dump());
|
||||
|
||||
break;
|
||||
}
|
||||
case "offer"_H: {
|
||||
std::string transmission_id = j["transmission_id"].get<std::string>();
|
||||
std::string sdp = j["sdp"].get<std::string>();
|
||||
std::string user_id = j["user_id"].get<std::string>();
|
||||
std::string remote_user_id = j["remote_user_id"].get<std::string>();
|
||||
|
||||
transmission_manager_.BindUserIdToTransmission(user_id, transmission_id);
|
||||
transmission_manager_.BindUserIdToWsHandle(user_id, hdl);
|
||||
|
||||
websocketpp::connection_hdl destination_hdl =
|
||||
transmission_manager_.GetWsHandle(remote_user_id);
|
||||
|
||||
json message = {{"type", "offer"},
|
||||
{"sdp", sdp},
|
||||
{"remote_user_id", user_id},
|
||||
{"transmission_id", transmission_id}};
|
||||
|
||||
LOG_INFO("[{}] send offer to [{}]", user_id, remote_user_id);
|
||||
send_msg(destination_hdl, message);
|
||||
|
||||
break;
|
||||
}
|
||||
case "answer"_H: {
|
||||
std::string transmission_id = j["transmission_id"].get<std::string>();
|
||||
std::string sdp = j["sdp"].get<std::string>();
|
||||
std::string user_id = j["user_id"].get<std::string>();
|
||||
std::string remote_user_id = j["remote_user_id"].get<std::string>();
|
||||
|
||||
websocketpp::connection_hdl destination_hdl =
|
||||
transmission_manager_.GetWsHandle(remote_user_id);
|
||||
|
||||
// LOG_INFO("send answer sdp [{}]", sdp);
|
||||
LOG_INFO("[{}] send answer to [{}]", user_id, remote_user_id);
|
||||
json message = {{"type", "answer"},
|
||||
{"sdp", sdp},
|
||||
{"remote_user_id", user_id},
|
||||
{"transmission_id", transmission_id}};
|
||||
send_msg(destination_hdl, message);
|
||||
break;
|
||||
}
|
||||
case "offer_candidate"_H: {
|
||||
std::string transmission_id = j["transmission_id"].get<std::string>();
|
||||
std::string candidate = j["sdp"].get<std::string>();
|
||||
LOG_INFO("send candidate [{}]", candidate.c_str());
|
||||
json message = {{"type", "candidate"}, {"sdp", candidate}};
|
||||
// send_msg(answer_hdl_map_[transmission_id], message);
|
||||
break;
|
||||
}
|
||||
case "answer_candidate"_H: {
|
||||
std::string transmission_id = j["transmission_id"].get<std::string>();
|
||||
std::string candidate = j["sdp"].get<std::string>();
|
||||
LOG_INFO("send candidate [{}]", candidate.c_str());
|
||||
json message = {{"type", "candidate"}, {"sdp", candidate}};
|
||||
// send_msg(offer_hdl_map_[transmission_id], message);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// std::string sdp = j["sdp"];
|
||||
|
||||
// LOG_INFO("Message type: {}", type);
|
||||
// LOG_INFO("Message body: {}", sdp);
|
||||
|
||||
// server_.send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#ifndef _SIGNAL_SERVER_H_
|
||||
#define _SIGNAL_SERVER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include "transmission_manager.h"
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
typedef unsigned int connection_id;
|
||||
typedef std::string room_id;
|
||||
|
||||
class SignalServer {
|
||||
public:
|
||||
SignalServer();
|
||||
~SignalServer();
|
||||
|
||||
bool on_open(websocketpp::connection_hdl hdl);
|
||||
|
||||
bool on_close(websocketpp::connection_hdl hdl);
|
||||
|
||||
bool on_ping(websocketpp::connection_hdl hdl, std::string s);
|
||||
|
||||
bool on_pong(websocketpp::connection_hdl hdl, std::string s);
|
||||
|
||||
void run(uint16_t port);
|
||||
|
||||
void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg);
|
||||
|
||||
void send_msg(websocketpp::connection_hdl hdl, json message);
|
||||
|
||||
private:
|
||||
server server_;
|
||||
std::map<websocketpp::connection_hdl, connection_id,
|
||||
std::owner_less<websocketpp::connection_hdl>>
|
||||
ws_connections_;
|
||||
std::map<room_id, connection_id> rooms_;
|
||||
unsigned int ws_connection_id_ = 0;
|
||||
|
||||
std::set<std::string> transmission_list_;
|
||||
TransmissionManager transmission_manager_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,168 +0,0 @@
|
||||
#include "transmission_manager.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
TransmissionManager::TransmissionManager() {}
|
||||
|
||||
TransmissionManager::~TransmissionManager() {}
|
||||
|
||||
std::vector<std::string> TransmissionManager::GetAllUserIdOfTransmission(
|
||||
const std::string& transmission_id) {
|
||||
if (transmission_user_id_list_.find(transmission_id) !=
|
||||
transmission_user_id_list_.end()) {
|
||||
return transmission_user_id_list_[transmission_id];
|
||||
}
|
||||
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
bool TransmissionManager::BindUserIdToTransmission(
|
||||
const std::string& user_id, const std::string& transmission_id) {
|
||||
if (transmission_user_id_list_.find(transmission_id) ==
|
||||
transmission_user_id_list_.end()) {
|
||||
transmission_user_id_list_[transmission_id].push_back(user_id);
|
||||
LOG_INFO("Bind user id [{}] to transmission [{}]", user_id,
|
||||
transmission_id);
|
||||
return true;
|
||||
} else {
|
||||
auto user_id_list = transmission_user_id_list_[transmission_id];
|
||||
for (auto id : user_id_list) {
|
||||
if (id == user_id) {
|
||||
LOG_WARN("User id [{}] already bind to transmission [{}]", user_id,
|
||||
transmission_id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
transmission_user_id_list_[transmission_id].push_back(user_id);
|
||||
LOG_INFO("Bind user id [{}] to transmission [{}]", user_id,
|
||||
transmission_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransmissionManager::BindPasswordToTransmission(
|
||||
const std::string& password, const std::string& transmission_id) {
|
||||
if (transmission_password_list_.find(transmission_id) ==
|
||||
transmission_password_list_.end()) {
|
||||
transmission_password_list_[transmission_id] = password;
|
||||
// LOG_INFO("Bind password [{}] to transmission [{}]", password,
|
||||
// transmission_id);
|
||||
return true;
|
||||
} else {
|
||||
auto old_password = transmission_password_list_[transmission_id];
|
||||
transmission_password_list_[transmission_id] = password;
|
||||
// LOG_WARN("Update password [{}] to [{}] for transmission [{}]",
|
||||
// old_password, password, transmission_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TransmissionManager::BindUserIdToWsHandle(
|
||||
const std::string& user_id, websocketpp::connection_hdl hdl) {
|
||||
if (user_id_ws_hdl_list_.find(user_id) != user_id_ws_hdl_list_.end()) {
|
||||
LOG_WARN("User id already bind to websocket handle [{}]", user_id,
|
||||
hdl.lock().get());
|
||||
return false;
|
||||
} else {
|
||||
user_id_ws_hdl_list_[user_id] = hdl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string TransmissionManager::ReleaseUserIdFromTransmission(
|
||||
websocketpp::connection_hdl hdl) {
|
||||
for (auto it = user_id_ws_hdl_list_.begin(); it != user_id_ws_hdl_list_.end();
|
||||
++it) {
|
||||
if (it->second.lock().get() == hdl.lock().get()) {
|
||||
for (auto trans_it = transmission_user_id_list_.begin();
|
||||
trans_it != transmission_user_id_list_.end(); ++trans_it) {
|
||||
auto& user_id_list = trans_it->second;
|
||||
auto user_id_it =
|
||||
std::find(user_id_list.begin(), user_id_list.end(), it->first);
|
||||
if (user_id_it != user_id_list.end()) {
|
||||
user_id_list.erase(user_id_it);
|
||||
LOG_INFO("Remove user id [{}] from transmission [{}]", it->first,
|
||||
trans_it->first);
|
||||
user_id_ws_hdl_list_.erase(it);
|
||||
return trans_it->first;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool TransmissionManager::ReleaseAllUserIdFromTransmission(
|
||||
const std::string& transmission_id) {
|
||||
if (transmission_user_id_list_.end() !=
|
||||
transmission_user_id_list_.find(transmission_id)) {
|
||||
auto user_id_list = transmission_user_id_list_[transmission_id];
|
||||
for (auto& user_id : user_id_list) {
|
||||
if (user_id_ws_hdl_list_.find(user_id) != user_id_ws_hdl_list_.end()) {
|
||||
LOG_INFO("Remove user id [{}] from transmission [{}]", user_id,
|
||||
transmission_id);
|
||||
user_id_ws_hdl_list_.erase(user_id);
|
||||
}
|
||||
}
|
||||
|
||||
user_id_list.clear();
|
||||
transmission_user_id_list_.erase(transmission_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransmissionManager::ReleasePasswordFromTransmission(
|
||||
const std::string& transmission_id) {
|
||||
if (transmission_password_list_.end() ==
|
||||
transmission_password_list_.find(transmission_id)) {
|
||||
LOG_ERROR("No transmission with id [{}]", transmission_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
transmission_password_list_.erase(transmission_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
websocketpp::connection_hdl TransmissionManager::GetWsHandle(
|
||||
const std::string& user_id) {
|
||||
if (user_id_ws_hdl_list_.find(user_id) != user_id_ws_hdl_list_.end()) {
|
||||
return user_id_ws_hdl_list_[user_id];
|
||||
} else {
|
||||
websocketpp::connection_hdl hdl;
|
||||
return hdl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string TransmissionManager::GetUserId(websocketpp::connection_hdl hdl) {
|
||||
for (auto it = user_id_ws_hdl_list_.begin(); it != user_id_ws_hdl_list_.end();
|
||||
++it) {
|
||||
// LOG_INFO("[{}]", it->first);
|
||||
if (it->second.lock().get() == hdl.lock().get()) return it->first;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool TransmissionManager::CheckPassword(const std::string& password,
|
||||
const std::string& transmission_id) {
|
||||
if (transmission_password_list_.find(transmission_id) ==
|
||||
transmission_password_list_.end()) {
|
||||
LOG_ERROR("No transmission with id [{}]", transmission_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
return transmission_password_list_[transmission_id] == password;
|
||||
}
|
||||
|
||||
std::string TransmissionManager::GetPassword(
|
||||
const std::string& transmission_id) {
|
||||
if (transmission_password_list_.find(transmission_id) ==
|
||||
transmission_password_list_.end()) {
|
||||
LOG_ERROR("No transmission with id [{}]", transmission_id);
|
||||
return "";
|
||||
}
|
||||
|
||||
return transmission_password_list_[transmission_id];
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef _TRANSIMISSION_MANAGER_H_
|
||||
#define _TRANSIMISSION_MANAGER_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
class TransmissionManager {
|
||||
public:
|
||||
TransmissionManager();
|
||||
~TransmissionManager();
|
||||
|
||||
public:
|
||||
std::vector<std::string> GetAllUserIdOfTransmission(
|
||||
const std::string& transmission_id);
|
||||
|
||||
public:
|
||||
bool BindUserIdToTransmission(const std::string& user_id,
|
||||
const std::string& transmission_id);
|
||||
bool BindPasswordToTransmission(const std::string& password,
|
||||
const std::string& transmission_id);
|
||||
bool BindUserIdToWsHandle(const std::string& user_id,
|
||||
websocketpp::connection_hdl hdl);
|
||||
|
||||
std::string ReleaseUserIdFromTransmission(websocketpp::connection_hdl hdl);
|
||||
bool ReleaseAllUserIdFromTransmission(const std::string& transmission_id);
|
||||
bool ReleasePasswordFromTransmission(const std::string& transmission_id);
|
||||
|
||||
websocketpp::connection_hdl GetWsHandle(const std::string& user_id);
|
||||
std::string GetUserId(websocketpp::connection_hdl hdl);
|
||||
bool CheckPassword(const std::string& password,
|
||||
const std::string& transmission_id);
|
||||
std::string GetPassword(const std::string& transmission_id);
|
||||
|
||||
private:
|
||||
std::map<std::string, std::vector<std::string>> transmission_user_id_list_;
|
||||
std::map<std::string, std::string> transmission_password_list_;
|
||||
std::map<std::string, websocketpp::connection_hdl> user_id_ws_hdl_list_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,43 +0,0 @@
|
||||
set_project("projectx")
|
||||
set_version("0.0.1")
|
||||
|
||||
add_rules("mode.release", "mode.debug")
|
||||
set_languages("c++17")
|
||||
|
||||
add_rules("mode.release", "mode.debug")
|
||||
|
||||
add_requires("asio 1.24.0", "nlohmann_json", "spdlog 1.11.0")
|
||||
|
||||
add_defines("ASIO_STANDALONE", "ASIO_HAS_STD_TYPE_TRAITS", "ASIO_HAS_STD_SHARED_PTR",
|
||||
"ASIO_HAS_STD_ADDRESSOF", "ASIO_HAS_STD_ATOMIC", "ASIO_HAS_STD_CHRONO", "ASIO_HAS_CSTDINT", "ASIO_HAS_STD_ARRAY",
|
||||
"ASIO_HAS_STD_SYSTEM_ERROR", "SIGNAL_LOGGER")
|
||||
|
||||
if is_os("windows") then
|
||||
add_defines("_WEBSOCKETPP_CPP11_INTERNAL_")
|
||||
add_links("ws2_32", "Bcrypt")
|
||||
add_requires("cuda")
|
||||
elseif is_os("linux") then
|
||||
add_links("pthread")
|
||||
set_config("cxxflags", "-fPIC")
|
||||
end
|
||||
|
||||
add_packages("spdlog")
|
||||
|
||||
includes("../../thirdparty")
|
||||
|
||||
target("log")
|
||||
set_kind("headeronly")
|
||||
add_packages("spdlog")
|
||||
add_headerfiles("../utils/log/log.h")
|
||||
add_includedirs("../utils/log", {public = true})
|
||||
|
||||
target("common")
|
||||
set_kind("headeronly")
|
||||
add_includedirs("../../src/common", {public = true})
|
||||
|
||||
target("signal_server")
|
||||
set_kind("binary")
|
||||
add_deps("log", "common")
|
||||
add_files("*.cpp")
|
||||
add_packages("asio", "nlohmann_json", "spdlog")
|
||||
add_includedirs("../../thirdparty/websocketpp/include")
|
||||
@@ -1,127 +0,0 @@
|
||||
#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
|
||||
439
xmake.lua
439
xmake.lua
@@ -31,239 +31,230 @@ add_requires("asio 1.24.0", "nlohmann_json", "spdlog 1.11.0", "openfec")
|
||||
add_packages("spdlog", "openfec")
|
||||
includes("thirdparty")
|
||||
|
||||
if has_config("server_only") then
|
||||
includes("application/signal_server")
|
||||
else
|
||||
if is_os("windows") then
|
||||
add_requires("vcpkg::ffmpeg 5.1.2", {configs = {shared = false}})
|
||||
add_requires("vcpkg::libnice 0.1.21")
|
||||
add_packages("vcpkg::libnice")
|
||||
add_requires("openh264 2.1.1", {configs = {shared = false}})
|
||||
elseif is_os("linux") then
|
||||
add_requires("ffmpeg 5.1.2", {system = false})
|
||||
add_requires("glib", {system = true})
|
||||
add_requires("vcpkg::libnice 0.1.21")
|
||||
add_requires("openh264 2.1.1", {configs = {shared = false}})
|
||||
add_packages("glib", "vcpkg::libnice")
|
||||
elseif is_os("macosx") then
|
||||
add_requires("ffmpeg 5.1.2", {system = false})
|
||||
add_requires("brew::libnice", "brew::glib")
|
||||
add_requires("brew::openh264", {configs = {shared = false}})
|
||||
end
|
||||
|
||||
target("log")
|
||||
set_kind("static")
|
||||
add_packages("spdlog")
|
||||
add_files("src/log/log.cpp")
|
||||
add_includedirs("src/log", {public = true})
|
||||
|
||||
target("common")
|
||||
set_kind("static")
|
||||
add_files("src/common/common.cpp")
|
||||
add_includedirs("src/common", {public = true})
|
||||
|
||||
target("inih")
|
||||
set_kind("static")
|
||||
add_files("src/inih/ini.c", "src/inih/INIReader.cpp")
|
||||
add_includedirs("src/inih", {public = true})
|
||||
|
||||
target("ringbuffer")
|
||||
set_kind("static")
|
||||
add_files("src/ringbuffer/ringbuffer.cpp")
|
||||
add_includedirs("src/ringbuffer", {public = true})
|
||||
|
||||
target("thread")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/thread/*.cpp")
|
||||
add_includedirs("src/thread", {public = true})
|
||||
|
||||
target("frame")
|
||||
set_kind("static")
|
||||
add_files("src/frame/*.cpp")
|
||||
add_includedirs("src/frame", {public = true})
|
||||
|
||||
target("fec")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/fec/*.cpp")
|
||||
add_includedirs("src/fec", {public = true})
|
||||
|
||||
target("rtcp")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/rtcp/*.cpp")
|
||||
add_includedirs("src/rtcp", {public = true})
|
||||
|
||||
target("rtp")
|
||||
set_kind("static")
|
||||
add_deps("log", "frame", "ringbuffer", "thread", "rtcp", "fec")
|
||||
add_files("src/rtp/*.cpp")
|
||||
add_includedirs("src/rtp", {public = true})
|
||||
|
||||
target("ice")
|
||||
set_kind("static")
|
||||
add_deps("log", "common", "ws")
|
||||
add_packages("asio", "nlohmann_json")
|
||||
add_files("src/ice/*.cpp")
|
||||
add_includedirs("src/ws", "src/ice", {public = true})
|
||||
if is_os("windows") then
|
||||
add_requires("vcpkg::ffmpeg 5.1.2", {configs = {shared = false}})
|
||||
add_requires("vcpkg::libnice 0.1.21")
|
||||
add_packages("vcpkg::libnice")
|
||||
add_requires("openh264 2.1.1", {configs = {shared = false}})
|
||||
elseif is_os("linux") then
|
||||
add_requires("ffmpeg 5.1.2", {system = false})
|
||||
add_requires("glib", {system = true})
|
||||
add_requires("vcpkg::libnice 0.1.21")
|
||||
add_requires("openh264 2.1.1", {configs = {shared = false}})
|
||||
add_packages("glib", "vcpkg::libnice")
|
||||
add_includedirs(path.join(os.getenv("VCPKG_ROOT"), "installed/x64-windows-static/include/glib-2.0"), {public = true})
|
||||
add_includedirs(path.join(os.getenv("VCPKG_ROOT"), "installed/x64-windows-static/lib/glib-2.0/include"), {public = true})
|
||||
add_links("nice", "glib-2.0", "gio-2.0", "gmodule-2.0", "gobject-2.0",
|
||||
"pcre2-8", "pcre2-16", "pcre2-32", "pcre2-posix",
|
||||
"zlib", "ffi", "libcrypto", "libssl", "intl", "iconv", "charset", "bz2",
|
||||
"Shell32", "Advapi32", "Dnsapi", "Shlwapi", "Iphlpapi")
|
||||
elseif is_os("macosx") then
|
||||
add_requires("ffmpeg 5.1.2", {system = false})
|
||||
add_requires("brew::libnice", "brew::glib")
|
||||
add_requires("brew::openh264", {configs = {shared = false}})
|
||||
add_packages("glib", "libnice")
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "glib/2.78.0/include/glib-2.0"), {public = true})
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "glib/2.78.0/lib/glib-2.0/include"), {public = true})
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "glib/2.78.0/lib/glib-2.0/include"), {public = true})
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "glib/2.78.0/include"), {public = true})
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "libnice/0.1.21/include"), {public = true})
|
||||
add_linkdirs(path.join("$(shell brew --cellar)", "glib/2.78.0/lib"))
|
||||
add_linkdirs(path.join("$(shell brew --cellar)", "libnice/0.1.21/lib"))
|
||||
add_links("nice", "glib-2.0", "gio-2.0", "gobject-2.0")
|
||||
end
|
||||
|
||||
target("ws")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/ws/*.cpp")
|
||||
add_packages("asio")
|
||||
add_includedirs("thirdparty/websocketpp/include", {public = true})
|
||||
|
||||
target("media")
|
||||
set_kind("static")
|
||||
add_deps("log", "frame")
|
||||
if is_os("windows") then
|
||||
add_packages("cuda", "vcpkg::ffmpeg", "openh264")
|
||||
add_files("src/media/video/encode/*.cpp",
|
||||
"src/media/video/decode/*.cpp",
|
||||
"src/media/video/encode/nvcodec/*.cpp",
|
||||
"src/media/video/decode/nvcodec/*.cpp",
|
||||
"src/media/video/encode/ffmpeg/*.cpp",
|
||||
"src/media/video/decode/ffmpeg/*.cpp",
|
||||
"src/media/video/encode/openh264/*.cpp",
|
||||
"src/media/video/decode/openh264/*.cpp")
|
||||
add_includedirs("src/media/video/encode",
|
||||
"src/media/video/decode",
|
||||
"src/media/video/encode/nvcodec",
|
||||
"src/media/video/decode/nvcodec",
|
||||
"src/media/video/encode/ffmpeg",
|
||||
"src/media/video/decode/ffmpeg",
|
||||
"src/media/video/encode/openh264",
|
||||
"src/media/video/decode/openh264",
|
||||
"thirdparty/nvcodec/Interface",
|
||||
"thirdparty/nvcodec/Samples", {public = true})
|
||||
add_linkdirs("thirdparty/nvcodec/Lib/x64")
|
||||
add_links("cuda", "nvencodeapi", "nvcuvid")
|
||||
elseif is_os(("linux")) then
|
||||
add_packages("cuda", "ffmpeg", "openh264")
|
||||
add_files("src/media/video/encode/*.cpp",
|
||||
"src/media/video/decode/*.cpp",
|
||||
"src/media/video/encode/nvcodec/*.cpp",
|
||||
"src/media/video/decode/nvcodec/*.cpp",
|
||||
"src/media/video/encode/ffmpeg/*.cpp",
|
||||
"src/media/video/decode/ffmpeg/*.cpp",
|
||||
"src/media/video/encode/openh264/*.cpp",
|
||||
"src/media/video/decode/openh264/*.cpp")
|
||||
add_includedirs("src/media/video/encode",
|
||||
"src/media/video/decode",
|
||||
"src/media/video/encode/nvcodec",
|
||||
"src/media/video/decode/nvcodec",
|
||||
"src/media/video/encode/ffmpeg",
|
||||
"src/media/video/decode/ffmpeg",
|
||||
"src/media/video/encode/openh264",
|
||||
"src/media/video/decode/openh264",
|
||||
"thirdparty/nvcodec/Interface",
|
||||
"thirdparty/nvcodec/Samples", {public = true})
|
||||
add_linkdirs("thirdparty/nvcodec/Lib/x64")
|
||||
add_links("cuda", "nvidia-encode", "nvcuvid")
|
||||
elseif is_os("macosx") then
|
||||
add_packages("ffmpeg")
|
||||
add_files("src/media/video/encode/*.cpp",
|
||||
"src/media/video/decode/*.cpp",
|
||||
"src/media/video/encode/ffmpeg/*.cpp",
|
||||
"src/media/video/decode/ffmpeg/*.cpp")
|
||||
add_includedirs("src/media/video/encode",
|
||||
"src/media/video/decode",
|
||||
"src/media/video/encode/ffmpeg",
|
||||
"src/media/video/decode/ffmpeg", {public = true})
|
||||
end
|
||||
|
||||
includes("application/remote_desk")
|
||||
-- includes("application/signal_server")
|
||||
target("qos")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/qos/kcp/*.c")
|
||||
add_includedirs("src/qos/kcp", {public = true})
|
||||
|
||||
target("log")
|
||||
set_kind("static")
|
||||
add_packages("spdlog")
|
||||
add_files("src/log/log.cpp")
|
||||
add_includedirs("src/log", {public = true})
|
||||
target("transmission")
|
||||
set_kind("static")
|
||||
add_deps("log", "ws", "ice", "qos", "rtp", "rtcp")
|
||||
add_files("src/transmission/*.cpp")
|
||||
add_packages("asio", "nlohmann_json")
|
||||
add_includedirs("src/ws", "src/ice", "src/qos", {public = true})
|
||||
|
||||
target("common")
|
||||
set_kind("static")
|
||||
add_files("src/common/common.cpp")
|
||||
add_includedirs("src/common", {public = true})
|
||||
target("pc")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_deps("ws", "ice", "transmission", "inih", "common", "media")
|
||||
add_files("src/pc/*.cpp")
|
||||
add_packages("asio", "nlohmann_json", "cuda")
|
||||
add_includedirs("src/transmission", "src/interface", {public = true})
|
||||
|
||||
target("inih")
|
||||
set_kind("static")
|
||||
add_files("src/inih/ini.c", "src/inih/INIReader.cpp")
|
||||
add_includedirs("src/inih", {public = true})
|
||||
target("projectx")
|
||||
set_kind("shared")
|
||||
add_deps("log")
|
||||
add_deps("pc")
|
||||
add_installfiles("src/interface/*.h", {prefixdir = "include"})
|
||||
add_files("src/rtc/*.cpp")
|
||||
add_packages("asio", "nlohmann_json", "cuda")
|
||||
add_includedirs("src/rtc", "src/pc", "src/interface")
|
||||
add_rules("utils.symbols.export_all", {export_classes = true})
|
||||
-- after_install(function (target)
|
||||
-- os.rm("$(projectdir)/out/lib/*.a")
|
||||
-- os.rm("$(projectdir)/out/include/log.h")
|
||||
-- end)
|
||||
|
||||
target("ringbuffer")
|
||||
set_kind("static")
|
||||
add_files("src/ringbuffer/ringbuffer.cpp")
|
||||
add_includedirs("src/ringbuffer", {public = true})
|
||||
-- target("host")
|
||||
-- set_kind("binary")
|
||||
-- add_deps("projectx")
|
||||
-- add_files("tests/peerconnection/host.cpp")
|
||||
-- add_includedirs("src/interface")
|
||||
|
||||
target("thread")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/thread/*.cpp")
|
||||
add_includedirs("src/thread", {public = true})
|
||||
-- target("guest")
|
||||
-- set_kind("binary")
|
||||
-- add_deps("projectx")
|
||||
-- add_files("tests/peerconnection/guest.cpp")
|
||||
-- add_includedirs("src/interface")
|
||||
|
||||
target("frame")
|
||||
set_kind("static")
|
||||
add_files("src/frame/*.cpp")
|
||||
add_includedirs("src/frame", {public = true})
|
||||
-- target("nicetest")
|
||||
-- set_kind("binary")
|
||||
-- add_files("tests/peerconnection/nice.cpp")
|
||||
-- add_includedirs("E:/SourceCode/vcpkg/installed/x64-windows-static/include/glib-2.0")
|
||||
-- add_includedirs("E:/SourceCode/vcpkg/installed/x64-windows-static/lib/glib-2.0/include")
|
||||
-- add_linkdirs("E:/SourceCode/vcpkg/installed/x64-windows-static/lib")
|
||||
-- add_links("nice", "glib-2.0", "gio-2.0", "gmodule-2.0", "gobject-2.0", "gthread-2.0",
|
||||
-- "pcre2-8", "pcre2-16", "pcre2-32", "pcre2-posix",
|
||||
-- "zlib", "ffi", "libcrypto", "libssl", "intl", "iconv", "charset", "bz2",
|
||||
-- "Shell32", "Advapi32", "Dnsapi", "Shlwapi", "Iphlpapi")
|
||||
|
||||
target("fec")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/fec/*.cpp")
|
||||
add_includedirs("src/fec", {public = true})
|
||||
-- target("fec_client")
|
||||
-- set_kind("binary")
|
||||
-- add_packages("openfec")
|
||||
-- add_files("tests/fec/simple_client.cpp")
|
||||
-- add_includedirs("tests/fec")
|
||||
|
||||
target("rtcp")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/rtcp/*.cpp")
|
||||
add_includedirs("src/rtcp", {public = true})
|
||||
|
||||
target("rtp")
|
||||
set_kind("static")
|
||||
add_deps("log", "frame", "ringbuffer", "thread", "rtcp", "fec")
|
||||
add_files("src/rtp/*.cpp")
|
||||
add_includedirs("src/rtp", {public = true})
|
||||
|
||||
target("ice")
|
||||
set_kind("static")
|
||||
add_deps("log", "common", "ws")
|
||||
add_packages("asio", "nlohmann_json")
|
||||
add_files("src/ice/*.cpp")
|
||||
add_includedirs("src/ws", "src/ice", {public = true})
|
||||
if is_os("windows") then
|
||||
add_includedirs(path.join(os.getenv("VCPKG_ROOT"), "installed/x64-windows-static/include/glib-2.0"), {public = true})
|
||||
add_includedirs(path.join(os.getenv("VCPKG_ROOT"), "installed/x64-windows-static/lib/glib-2.0/include"), {public = true})
|
||||
add_links("nice", "glib-2.0", "gio-2.0", "gmodule-2.0", "gobject-2.0",
|
||||
"pcre2-8", "pcre2-16", "pcre2-32", "pcre2-posix",
|
||||
"zlib", "ffi", "libcrypto", "libssl", "intl", "iconv", "charset", "bz2",
|
||||
"Shell32", "Advapi32", "Dnsapi", "Shlwapi", "Iphlpapi")
|
||||
elseif is_os("macosx") then
|
||||
add_packages("glib", "libnice")
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "glib/2.78.0/include/glib-2.0"), {public = true})
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "glib/2.78.0/lib/glib-2.0/include"), {public = true})
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "glib/2.78.0/lib/glib-2.0/include"), {public = true})
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "glib/2.78.0/include"), {public = true})
|
||||
add_includedirs(path.join("$(shell brew --cellar)", "libnice/0.1.21/include"), {public = true})
|
||||
add_linkdirs(path.join("$(shell brew --cellar)", "glib/2.78.0/lib"))
|
||||
add_linkdirs(path.join("$(shell brew --cellar)", "libnice/0.1.21/lib"))
|
||||
add_links("nice", "glib-2.0", "gio-2.0", "gobject-2.0")
|
||||
end
|
||||
|
||||
|
||||
target("ws")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/ws/*.cpp")
|
||||
add_packages("asio")
|
||||
add_includedirs("thirdparty/websocketpp/include", {public = true})
|
||||
|
||||
target("media")
|
||||
set_kind("static")
|
||||
add_deps("log", "frame")
|
||||
if is_os("windows") then
|
||||
add_packages("cuda", "vcpkg::ffmpeg", "openh264")
|
||||
add_files("src/media/video/encode/*.cpp",
|
||||
"src/media/video/decode/*.cpp",
|
||||
"src/media/video/encode/nvcodec/*.cpp",
|
||||
"src/media/video/decode/nvcodec/*.cpp",
|
||||
"src/media/video/encode/ffmpeg/*.cpp",
|
||||
"src/media/video/decode/ffmpeg/*.cpp",
|
||||
"src/media/video/encode/openh264/*.cpp",
|
||||
"src/media/video/decode/openh264/*.cpp")
|
||||
add_includedirs("src/media/video/encode",
|
||||
"src/media/video/decode",
|
||||
"src/media/video/encode/nvcodec",
|
||||
"src/media/video/decode/nvcodec",
|
||||
"src/media/video/encode/ffmpeg",
|
||||
"src/media/video/decode/ffmpeg",
|
||||
"src/media/video/encode/openh264",
|
||||
"src/media/video/decode/openh264",
|
||||
"thirdparty/nvcodec/Interface",
|
||||
"thirdparty/nvcodec/Samples", {public = true})
|
||||
add_linkdirs("thirdparty/nvcodec/Lib/x64")
|
||||
add_links("cuda", "nvencodeapi", "nvcuvid")
|
||||
elseif is_os(("linux")) then
|
||||
add_packages("cuda", "ffmpeg", "openh264")
|
||||
add_files("src/media/video/encode/*.cpp",
|
||||
"src/media/video/decode/*.cpp",
|
||||
"src/media/video/encode/nvcodec/*.cpp",
|
||||
"src/media/video/decode/nvcodec/*.cpp",
|
||||
"src/media/video/encode/ffmpeg/*.cpp",
|
||||
"src/media/video/decode/ffmpeg/*.cpp",
|
||||
"src/media/video/encode/openh264/*.cpp",
|
||||
"src/media/video/decode/openh264/*.cpp")
|
||||
add_includedirs("src/media/video/encode",
|
||||
"src/media/video/decode",
|
||||
"src/media/video/encode/nvcodec",
|
||||
"src/media/video/decode/nvcodec",
|
||||
"src/media/video/encode/ffmpeg",
|
||||
"src/media/video/decode/ffmpeg",
|
||||
"src/media/video/encode/openh264",
|
||||
"src/media/video/decode/openh264",
|
||||
"thirdparty/nvcodec/Interface",
|
||||
"thirdparty/nvcodec/Samples", {public = true})
|
||||
add_linkdirs("thirdparty/nvcodec/Lib/x64")
|
||||
add_links("cuda", "nvidia-encode", "nvcuvid")
|
||||
elseif is_os("macosx") then
|
||||
add_packages("ffmpeg")
|
||||
add_files("src/media/video/encode/*.cpp",
|
||||
"src/media/video/decode/*.cpp",
|
||||
"src/media/video/encode/ffmpeg/*.cpp",
|
||||
"src/media/video/decode/ffmpeg/*.cpp")
|
||||
add_includedirs("src/media/video/encode",
|
||||
"src/media/video/decode",
|
||||
"src/media/video/encode/ffmpeg",
|
||||
"src/media/video/decode/ffmpeg", {public = true})
|
||||
end
|
||||
|
||||
target("qos")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_files("src/qos/kcp/*.c")
|
||||
add_includedirs("src/qos/kcp", {public = true})
|
||||
|
||||
target("transmission")
|
||||
set_kind("static")
|
||||
add_deps("log", "ws", "ice", "qos", "rtp", "rtcp")
|
||||
add_files("src/transmission/*.cpp")
|
||||
add_packages("asio", "nlohmann_json")
|
||||
add_includedirs("src/ws", "src/ice", "src/qos", {public = true})
|
||||
|
||||
target("pc")
|
||||
set_kind("static")
|
||||
add_deps("log")
|
||||
add_deps("ws", "ice", "transmission", "inih", "common", "media")
|
||||
add_files("src/pc/*.cpp")
|
||||
add_packages("asio", "nlohmann_json", "cuda")
|
||||
add_includedirs("src/transmission", "src/interface", {public = true})
|
||||
|
||||
|
||||
target("projectx")
|
||||
set_kind("shared")
|
||||
add_deps("log")
|
||||
add_deps("pc")
|
||||
add_installfiles("src/interface/*.h", {prefixdir = "include"})
|
||||
add_files("src/rtc/*.cpp")
|
||||
add_packages("asio", "nlohmann_json", "cuda")
|
||||
add_includedirs("src/rtc", "src/pc", "src/interface")
|
||||
add_rules("utils.symbols.export_all", {export_classes = true})
|
||||
-- after_install(function (target)
|
||||
-- os.rm("$(projectdir)/out/lib/*.a")
|
||||
-- os.rm("$(projectdir)/out/include/log.h")
|
||||
-- end)
|
||||
|
||||
-- target("host")
|
||||
-- set_kind("binary")
|
||||
-- add_deps("projectx")
|
||||
-- add_files("tests/peerconnection/host.cpp")
|
||||
-- add_includedirs("src/interface")
|
||||
|
||||
-- target("guest")
|
||||
-- set_kind("binary")
|
||||
-- add_deps("projectx")
|
||||
-- add_files("tests/peerconnection/guest.cpp")
|
||||
-- add_includedirs("src/interface")
|
||||
|
||||
-- target("nicetest")
|
||||
-- set_kind("binary")
|
||||
-- add_files("tests/peerconnection/nice.cpp")
|
||||
-- add_includedirs("E:/SourceCode/vcpkg/installed/x64-windows-static/include/glib-2.0")
|
||||
-- add_includedirs("E:/SourceCode/vcpkg/installed/x64-windows-static/lib/glib-2.0/include")
|
||||
-- add_linkdirs("E:/SourceCode/vcpkg/installed/x64-windows-static/lib")
|
||||
-- add_links("nice", "glib-2.0", "gio-2.0", "gmodule-2.0", "gobject-2.0", "gthread-2.0",
|
||||
-- "pcre2-8", "pcre2-16", "pcre2-32", "pcre2-posix",
|
||||
-- "zlib", "ffi", "libcrypto", "libssl", "intl", "iconv", "charset", "bz2",
|
||||
-- "Shell32", "Advapi32", "Dnsapi", "Shlwapi", "Iphlpapi")
|
||||
|
||||
-- target("fec_client")
|
||||
-- set_kind("binary")
|
||||
-- add_packages("openfec")
|
||||
-- add_files("tests/fec/simple_client.cpp")
|
||||
-- add_includedirs("tests/fec")
|
||||
|
||||
-- target("fec_server")
|
||||
-- set_kind("binary")
|
||||
-- add_packages("openfec")
|
||||
-- add_files("tests/fec/simple_server.cpp")
|
||||
-- add_includedirs("tests/fec")
|
||||
end
|
||||
-- target("fec_server")
|
||||
-- set_kind("binary")
|
||||
-- add_packages("openfec")
|
||||
-- add_files("tests/fec/simple_server.cpp")
|
||||
-- add_includedirs("tests/fec")
|
||||
Reference in New Issue
Block a user