diff --git a/src/gui/main.cpp b/src/gui/main.cpp index af7dfac..6d72349 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -8,6 +8,8 @@ #endif #endif +#include + #include #include #include @@ -16,22 +18,13 @@ #include #include -#include "platform.h" - -extern "C" { -#include -#include -#include -}; - -#include - #include "../../thirdparty/projectx/src/interface/x.h" #include "device_controller_factory.h" #include "imgui.h" #include "imgui_impl_sdl2.h" #include "imgui_impl_sdlrenderer2.h" #include "log.h" +#include "platform.h" #include "screen_capturer_factory.h" #define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2 @@ -62,22 +55,22 @@ int fps = 0; static std::atomic audio_buffer_fresh{false}; static uint32_t last_ts = 0; -int64_t src_ch_layout = AV_CH_LAYOUT_MONO; -int src_rate = 48000; -enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_S16; -int src_nb_channels = 0; -uint8_t **src_data = NULL; -int src_linesize; -int src_nb_samples = 480; +// int64_t src_ch_layout = AV_CH_LAYOUT_MONO; +// int src_rate = 48000; +// enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_S16; +// int src_nb_channels = 0; +// uint8_t **src_data = NULL; +// int src_linesize; +// int src_nb_samples = 480; -int64_t dst_ch_layout = AV_CH_LAYOUT_MONO; -int dst_rate = 48000; -enum AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_S16; -int dst_nb_channels = 0; -uint8_t **dst_data = NULL; -int dst_linesize; -int dst_nb_samples; -int max_dst_nb_samples; +// int64_t dst_ch_layout = AV_CH_LAYOUT_MONO; +// int dst_rate = 48000; +// enum AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_S16; +// int dst_nb_channels = 0; +// uint8_t **dst_data = NULL; +// int dst_linesize; +// int dst_nb_samples; +// int max_dst_nb_samples; int dst_bufsize; struct SwrContext *swr_ctx; @@ -194,46 +187,47 @@ inline int ProcessMouseKeyEven(SDL_Event &ev) { } void SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len) { - int64_t delay = swr_get_delay(swr_ctx, src_rate); - dst_nb_samples = (int)av_rescale_rnd(delay + src_nb_samples, dst_rate, - src_rate, AV_ROUND_UP); - if (dst_nb_samples > max_dst_nb_samples) { - av_freep(&dst_data[0]); - ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels, - dst_nb_samples, dst_sample_fmt, 1); - if (ret < 0) return; - max_dst_nb_samples = dst_nb_samples; - } + // int64_t delay = swr_get_delay(swr_ctx, src_rate); + // dst_nb_samples = (int)av_rescale_rnd(delay + src_nb_samples, dst_rate, + // src_rate, AV_ROUND_UP); + // if (dst_nb_samples > max_dst_nb_samples) { + // av_freep(&dst_data[0]); + // ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels, + // dst_nb_samples, dst_sample_fmt, 1); + // if (ret < 0) return; + // max_dst_nb_samples = dst_nb_samples; + // } - ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, - (const uint8_t **)&stream, src_nb_samples); - if (ret < 0) { - fprintf(stderr, "Error while converting\n"); - return; - } - dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels, ret, - dst_sample_fmt, 1); - if (dst_bufsize < 0) { - fprintf(stderr, "Could not get sample buffer size\n"); - return; - } + // ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, + // (const uint8_t **)&stream, src_nb_samples); + // if (ret < 0) { + // fprintf(stderr, "Error while converting\n"); + // return; + // } + // dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels, + // ret, + // dst_sample_fmt, 1); + // if (dst_bufsize < 0) { + // fprintf(stderr, "Could not get sample buffer size\n"); + // return; + // } - if (1) { - if ("ClientConnected" == client_connection_status_str) { - SendData(peer_client, DATA_TYPE::AUDIO, (const char *)dst_data[0], - dst_bufsize); - } + // if (1) { + // if ("ClientConnected" == client_connection_status_str) { + // SendData(peer_client, DATA_TYPE::AUDIO, (const char *)dst_data[0], + // dst_bufsize); + // } - if ("ServerConnected" == server_connection_status_str) { - SendData(peer_server, DATA_TYPE::AUDIO, (const char *)dst_data[0], - dst_bufsize); - } - } else { - memcpy(audio_buffer, dst_data[0], dst_bufsize); - audio_len = dst_bufsize; - SDL_Delay(10); - audio_buffer_fresh = true; - } + // if ("ServerConnected" == server_connection_status_str) { + // SendData(peer_server, DATA_TYPE::AUDIO, (const char *)dst_data[0], + // dst_bufsize); + // } + // } else { + // memcpy(audio_buffer, dst_data[0], dst_bufsize); + // audio_len = dst_bufsize; + // SDL_Delay(10); + // audio_buffer_fresh = true; + // } } void SdlCaptureAudioOut(void *userdata, Uint8 *stream, int len) { @@ -394,52 +388,52 @@ void ClientConnectionStatus(ConnectionStatus status) { int initResampler() { /* create resampler context */ - swr_ctx = swr_alloc(); - if (!swr_ctx) { - fprintf(stderr, "Could not allocate resampler context\n"); - ret = AVERROR(ENOMEM); - return -1; - } + // swr_ctx = swr_alloc(); + // if (!swr_ctx) { + // fprintf(stderr, "Could not allocate resampler context\n"); + // ret = AVERROR(ENOMEM); + // return -1; + // } - /* set options */ - av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0); - av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0); - av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0); + // /* set options */ + // av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0); + // av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0); + // av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0); - av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0); - av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0); - av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0); + // av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0); + // av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0); + // av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0); - /* initialize the resampling context */ - if ((ret = swr_init(swr_ctx)) < 0) { - fprintf(stderr, "Failed to initialize the resampling context\n"); - return -1; - } + // /* initialize the resampling context */ + // if ((ret = swr_init(swr_ctx)) < 0) { + // fprintf(stderr, "Failed to initialize the resampling context\n"); + // return -1; + // } - /* allocate source and destination samples buffers */ - src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout); + // /* allocate source and destination samples buffers */ + // src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout); - ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, - src_nb_channels, src_nb_samples, - src_sample_fmt, 0); - if (ret < 0) { - fprintf(stderr, "Could not allocate source samples\n"); - return -1; - } + // ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, + // src_nb_channels, src_nb_samples, + // src_sample_fmt, 0); + // if (ret < 0) { + // fprintf(stderr, "Could not allocate source samples\n"); + // return -1; + // } - max_dst_nb_samples = dst_nb_samples = - av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP); + // max_dst_nb_samples = dst_nb_samples = + // av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP); - /* buffer is going to be directly written to a rawaudio file, no alignment */ - dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout); + // /* buffer is going to be directly written to a rawaudio file, no alignment + // */ dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout); - ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, - dst_nb_channels, dst_nb_samples, - dst_sample_fmt, 0); - if (ret < 0) { - fprintf(stderr, "Could not allocate destination samples\n"); - return -1; - } + // ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, + // dst_nb_channels, dst_nb_samples, + // dst_sample_fmt, 0); + // if (ret < 0) { + // fprintf(stderr, "Could not allocate destination samples\n"); + // return -1; + // } return 0; } @@ -447,329 +441,263 @@ int initResampler() { int main(int argc, char *argv[]) { LOG_INFO("Remote desk"); - last_ts = static_cast( - std::chrono::duration_cast( - std::chrono::high_resolution_clock::now().time_since_epoch()) - .count()); + last_ts = static_cast( + std::chrono::duration_cast( + std::chrono::high_resolution_clock::now().time_since_epoch()) + .count()); - initResampler(); + initResampler(); - cd_cache_file = fopen("cache.cd", "r+"); - if (cd_cache_file) { - fseek(cd_cache_file, 0, SEEK_SET); - fread(&cd_cache.password, sizeof(cd_cache.password), 1, cd_cache_file); - fclose(cd_cache_file); - strncpy(input_password, cd_cache.password, sizeof(cd_cache.password)); - } + cd_cache_file = fopen("cache.cd", "r+"); + if (cd_cache_file) { + fseek(cd_cache_file, 0, SEEK_SET); + fread(&cd_cache.password, sizeof(cd_cache.password), 1, cd_cache_file); + fclose(cd_cache_file); + strncpy(input_password, cd_cache.password, sizeof(cd_cache.password)); + } - // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | - SDL_INIT_GAMECONTROLLER) != 0) { - printf("Error: %s\n", SDL_GetError()); - return -1; - } + // Setup SDL + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | 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 + // 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); + // 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; + 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; - } + 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; + Uint32 pixformat = 0; + pixformat = SDL_PIXELFORMAT_NV12; - sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, - SDL_TEXTUREACCESS_STREAMING, pixel_w, - pixel_h); + sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, + SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h); - // Audio - SDL_AudioSpec want_in, have_in, want_out, have_out; - SDL_zero(want_in); - want_in.freq = 48000; - want_in.format = AUDIO_S16LSB; - want_in.channels = 1; - want_in.samples = 480; - want_in.callback = SdlCaptureAudioIn; + // Audio + SDL_AudioSpec want_in, have_in, want_out, have_out; + SDL_zero(want_in); + want_in.freq = 48000; + want_in.format = AUDIO_S16LSB; + want_in.channels = 1; + want_in.samples = 480; + want_in.callback = SdlCaptureAudioIn; - input_dev = SDL_OpenAudioDevice(NULL, 1, &want_in, &have_in, 0); - if (input_dev == 0) { - SDL_Log("Failed to open input: %s", SDL_GetError()); - // return 1; - } + input_dev = SDL_OpenAudioDevice(NULL, 1, &want_in, &have_in, 0); + if (input_dev == 0) { + SDL_Log("Failed to open input: %s", SDL_GetError()); + // return 1; + } - SDL_zero(want_out); - want_out.freq = 48000; - want_out.format = AUDIO_S16LSB; - want_out.channels = 1; - // want_out.silence = 0; - want_out.samples = 480; - want_out.callback = NULL; + SDL_zero(want_out); + want_out.freq = 48000; + want_out.format = AUDIO_S16LSB; + want_out.channels = 1; + // want_out.silence = 0; + want_out.samples = 480; + want_out.callback = NULL; - output_dev = SDL_OpenAudioDevice(NULL, 0, &want_out, &have_out, 0); - if (output_dev == 0) { - SDL_Log("Failed to open input: %s", SDL_GetError()); - // return 1; - } + output_dev = SDL_OpenAudioDevice(NULL, 0, &want_out, &have_out, 0); + if (output_dev == 0) { + SDL_Log("Failed to open input: %s", SDL_GetError()); + // return 1; + } - SDL_PauseAudioDevice(input_dev, 0); - SDL_PauseAudioDevice(output_dev, 0); + SDL_PauseAudioDevice(input_dev, 0); + SDL_PauseAudioDevice(output_dev, 0); - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO &io = ImGui::GetIO(); + // 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 + io.ConfigFlags |= + ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= + ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - // Setup Dear ImGui style - ImGui::StyleColorsDark(); - // ImGui::StyleColorsLight(); + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + // ImGui::StyleColorsLight(); - // Setup Platform/Renderer backends - ImGui_ImplSDL2_InitForSDLRenderer(window, sdlRenderer); - ImGui_ImplSDLRenderer2_Init(sdlRenderer); + // 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); + // Our state + bool show_demo_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - std::string mac_addr_str = GetMac(); + std::string mac_addr_str = GetMac(); - std::thread rtc_thread( - [](int screen_width, int screen_height) { - std::string default_cfg_path = "../../../../config/config.ini"; - std::ifstream f(default_cfg_path.c_str()); + std::thread rtc_thread( + [](int screen_width, int screen_height) { + std::string default_cfg_path = "../../../../config/config.ini"; + std::ifstream f(default_cfg_path.c_str()); - std::string mac_addr_str = GetMac(); + std::string mac_addr_str = GetMac(); - Params server_params; - server_params.cfg_path = - f.good() ? "../../../../config/config.ini" : "config.ini"; - server_params.on_receive_video_buffer = ServerReceiveVideoBuffer; - server_params.on_receive_audio_buffer = ServerReceiveAudioBuffer; - server_params.on_receive_data_buffer = ServerReceiveDataBuffer; - server_params.on_signal_status = ServerSignalStatus; - server_params.on_connection_status = ServerConnectionStatus; + Params server_params; + server_params.cfg_path = + f.good() ? "../../../../config/config.ini" : "config.ini"; + server_params.on_receive_video_buffer = ServerReceiveVideoBuffer; + server_params.on_receive_audio_buffer = ServerReceiveAudioBuffer; + server_params.on_receive_data_buffer = ServerReceiveDataBuffer; + server_params.on_signal_status = ServerSignalStatus; + server_params.on_connection_status = ServerConnectionStatus; - Params client_params; - client_params.cfg_path = - f.good() ? "../../../../config/config.ini" : "config.ini"; - client_params.on_receive_video_buffer = ClientReceiveVideoBuffer; - client_params.on_receive_audio_buffer = ClientReceiveAudioBuffer; - client_params.on_receive_data_buffer = ClientReceiveDataBuffer; - client_params.on_signal_status = ClientSignalStatus; - client_params.on_connection_status = ClientConnectionStatus; + Params client_params; + client_params.cfg_path = + f.good() ? "../../../../config/config.ini" : "config.ini"; + client_params.on_receive_video_buffer = ClientReceiveVideoBuffer; + client_params.on_receive_audio_buffer = ClientReceiveAudioBuffer; + client_params.on_receive_data_buffer = ClientReceiveDataBuffer; + client_params.on_signal_status = ClientSignalStatus; + client_params.on_connection_status = ClientConnectionStatus; - std::string transmission_id = "000001"; + std::string transmission_id = "000001"; - peer_server = CreatePeer(&server_params); - LOG_INFO("Create peer_server"); - std::string server_user_id = "S-" + mac_addr_str; - Init(peer_server, server_user_id.c_str()); - LOG_INFO("peer_server init finish"); + peer_server = CreatePeer(&server_params); + LOG_INFO("Create peer_server"); + std::string server_user_id = "S-" + mac_addr_str; + Init(peer_server, server_user_id.c_str()); + LOG_INFO("peer_server init finish"); - peer_client = CreatePeer(&client_params); - LOG_INFO("Create peer_client"); - std::string client_user_id = "C-" + mac_addr_str; - Init(peer_client, client_user_id.c_str()); - LOG_INFO("peer_client init finish"); - - { - while (SignalStatus::SignalConnected != server_signal_status && - !done) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - - if (done) { - return; - } - - std::string user_id = "S-" + mac_addr_str; - is_create_connection = - CreateConnection(peer_server, mac_addr_str.c_str(), - input_password) - ? false - : true; - - nv12_buffer = new char[NV12_BUFFER_SIZE]; - - // Screen capture - screen_capturer_factory = new ScreenCapturerFactory(); - screen_capturer = (ScreenCapturer - *)screen_capturer_factory->Create(); - - last_frame_time_ = std::chrono::high_resolution_clock::now(); - ScreenCapturer::RECORD_DESKTOP_RECT rect; - rect.left = 0; - rect.top = 0; - rect.right = screen_w; - rect.bottom = screen_h; - - screen_capturer->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 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_capturer->Start(); - - // Mouse control - device_controller_factory = new DeviceControllerFactory(); - mouse_controller = - (MouseController *)device_controller_factory->Create( - DeviceControllerFactory::Device::Mouse); - mouse_controller->Init(screen_w, screen_h); - } - }, - screen_w, screen_h); - - // Main loop - while (!done) { - // Start the Dear ImGui frame - ImGui_ImplSDLRenderer2_NewFrame(); - ImGui_ImplSDL2_NewFrame(); - ImGui::NewFrame(); - - if (joined && !menu_hovered) { - ImGui::SetMouseCursor(ImGuiMouseCursor_None); - } - - { - 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(190, 200)); - - ImGui::Begin("Menu", nullptr, ImGuiWindowFlags_NoResize); + peer_client = CreatePeer(&client_params); + LOG_INFO("Create peer_client"); + std::string client_user_id = "C-" + mac_addr_str; + Init(peer_client, client_user_id.c_str()); + LOG_INFO("peer_client init finish"); { - menu_hovered = ImGui::IsWindowHovered(); - ImGui::Text(" LOCAL ID:"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(95); - ImGui::InputText( - "##local_id", (char *)mac_addr_str.c_str(), - mac_addr_str.length() + 1, - ImGuiInputTextFlags_CharsUppercase | - ImGuiInputTextFlags_ReadOnly); - - ImGui::Text(" PASSWORD:"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(95); - - char input_password_tmp[7] = ""; - strncpy(input_password_tmp, input_password, - sizeof(input_password)); - - ImGui::InputTextWithHint("##server_pwd", "max 6 chars", - input_password, - IM_ARRAYSIZE(input_password), - ImGuiInputTextFlags_CharsNoBlank); - if (strcmp(input_password_tmp, input_password)) { - cd_cache_file = fopen("cache.cd", "w+"); - if (cd_cache_file) { - fseek(cd_cache_file, 0, SEEK_SET); - strncpy(cd_cache.password, input_password, - sizeof(input_password)); fwrite(&cd_cache.password, - sizeof(cd_cache.password), 1, - cd_cache_file); - fclose(cd_cache_file); - } - LeaveConnection(peer_server); - CreateConnection(peer_server, mac_addr_str.c_str(), - input_password); + while (SignalStatus::SignalConnected != server_signal_status && + !done) { + std::this_thread::sleep_for(std::chrono::seconds(1)); } - ImGui::Spacing(); + if (done) { + return; + } - ImGui::Separator(); + std::string user_id = "S-" + mac_addr_str; + is_create_connection = + CreateConnection(peer_server, mac_addr_str.c_str(), + input_password) + ? false + : true; - ImGui::Spacing(); - { - { - static char remote_id[20] = ""; - ImGui::Text("REMOTE ID:"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(95); - ImGui::InputTextWithHint("##remote_id", mac_addr_str.c_str(), - remote_id, IM_ARRAYSIZE(remote_id), - ImGuiInputTextFlags_CharsUppercase | - ImGuiInputTextFlags_CharsNoBlank); + nv12_buffer = new char[NV12_BUFFER_SIZE]; - ImGui::Spacing(); + // Screen capture + screen_capturer_factory = new ScreenCapturerFactory(); + screen_capturer = (ScreenCapturer *)screen_capturer_factory->Create(); - ImGui::Text(" PASSWORD:"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(95); - static char client_password[20] = ""; - ImGui::InputTextWithHint("##client_pwd", "max 6 chars", - client_password, - IM_ARRAYSIZE(client_password), - ImGuiInputTextFlags_CharsNoBlank); + last_frame_time_ = std::chrono::high_resolution_clock::now(); + ScreenCapturer::RECORD_DESKTOP_RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = screen_w; + rect.bottom = screen_h; - if (ImGui::Button(connect_label)) { - int ret = -1; - if ("ClientSignalConnected" == client_signal_status_str) { - if (strcmp(connect_label, "Connect") == 0 && !joined) { - std::string user_id = "C-" + mac_addr_str; - ret = JoinConnection(peer_client, remote_id, - client_password); if (0 == ret) { - // joined = true; - } - } else if (strcmp(connect_label, "Disconnect") == 0 && - joined) { - ret = LeaveConnection(peer_client); - memset(audio_buffer, 0, 960); - if (0 == ret) { - joined = false; - received_frame = false; - } - } + screen_capturer->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 duration = + now_time - last_frame_time_; + auto tc = duration.count() * 1000; - if (0 == ret) { - connect_button_pressed = !connect_button_pressed; - connect_label = - connect_button_pressed ? "Disconnect" : "Connect"; - } + if (tc >= 0) { + SendData(peer_server, DATA_TYPE::VIDEO, (const char *)data, + NV12_BUFFER_SIZE); + last_frame_time_ = now_time; } - } - } + }); + + screen_capturer->Start(); + + // Mouse control + device_controller_factory = new DeviceControllerFactory(); + mouse_controller = + (MouseController *)device_controller_factory->Create( + DeviceControllerFactory::Device::Mouse); + mouse_controller->Init(screen_w, screen_h); + } + }, + screen_w, screen_h); + + // Main loop + while (!done) { + // Start the Dear ImGui frame + ImGui_ImplSDLRenderer2_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + + if (joined && !menu_hovered) { + ImGui::SetMouseCursor(ImGuiMouseCursor_None); + } + + { + 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(190, 200)); + + ImGui::Begin("Menu", nullptr, ImGuiWindowFlags_NoResize); + + { + menu_hovered = ImGui::IsWindowHovered(); + ImGui::Text(" LOCAL ID:"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(95); + ImGui::InputText( + "##local_id", (char *)mac_addr_str.c_str(), + mac_addr_str.length() + 1, + ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_ReadOnly); + + ImGui::Text(" PASSWORD:"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(95); + + char input_password_tmp[7] = ""; + strncpy(input_password_tmp, input_password, sizeof(input_password)); + + ImGui::InputTextWithHint("##server_pwd", "max 6 chars", input_password, + IM_ARRAYSIZE(input_password), + ImGuiInputTextFlags_CharsNoBlank); + if (strcmp(input_password_tmp, input_password)) { + cd_cache_file = fopen("cache.cd", "w+"); + if (cd_cache_file) { + fseek(cd_cache_file, 0, SEEK_SET); + strncpy(cd_cache.password, input_password, sizeof(input_password)); + fwrite(&cd_cache.password, sizeof(cd_cache.password), 1, + cd_cache_file); + fclose(cd_cache_file); } + LeaveConnection(peer_server); + CreateConnection(peer_server, mac_addr_str.c_str(), input_password); } ImGui::Spacing(); @@ -777,108 +705,164 @@ int main(int argc, char *argv[]) { ImGui::Separator(); ImGui::Spacing(); - { - if (ImGui::Button("Resize Window")) { - SDL_GetWindowSize(window, &window_w, &window_h); + { + static char remote_id[20] = ""; + ImGui::Text("REMOTE ID:"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(95); + ImGui::InputTextWithHint("##remote_id", mac_addr_str.c_str(), + remote_id, IM_ARRAYSIZE(remote_id), + ImGuiInputTextFlags_CharsUppercase | + ImGuiInputTextFlags_CharsNoBlank); - if (window_h != window_w * 9 / 16) { - window_w = window_h * 16 / 9; + ImGui::Spacing(); + + ImGui::Text(" PASSWORD:"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(95); + static char client_password[20] = ""; + ImGui::InputTextWithHint("##client_pwd", "max 6 chars", + client_password, + IM_ARRAYSIZE(client_password), + ImGuiInputTextFlags_CharsNoBlank); + + if (ImGui::Button(connect_label)) { + int ret = -1; + if ("ClientSignalConnected" == client_signal_status_str) { + if (strcmp(connect_label, "Connect") == 0 && !joined) { + std::string user_id = "C-" + mac_addr_str; + ret = JoinConnection(peer_client, remote_id, client_password); + if (0 == ret) { + // joined = true; + } + } else if (strcmp(connect_label, "Disconnect") == 0 && joined) { + ret = LeaveConnection(peer_client); + memset(audio_buffer, 0, 960); + if (0 == ret) { + joined = false; + received_frame = false; + } + } + + if (0 == ret) { + connect_button_pressed = !connect_button_pressed; + connect_label = + connect_button_pressed ? "Disconnect" : "Connect"; + } + } } - - SDL_SetWindowSize(window, window_w, window_h); } } - - ImGui::End(); } - // Rendering - ImGui::Render(); - SDL_RenderSetScale(sdlRenderer, io.DisplayFramebufferScale.x, - io.DisplayFramebufferScale.y); + ImGui::Spacing(); - 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) { + ImGui::Separator(); + + ImGui::Spacing(); + + { + if (ImGui::Button("Resize Window")) { SDL_GetWindowSize(window, &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); + 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); + } 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_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 [" + server_signal_status_str + "|" + - client_signal_status_str + "|" + - server_connection_status_str + "|" + - client_connection_status_str + "]"; - // For MacOS, UI frameworks can only be called from the main thread - SDL_SetWindowTitle(window, window_title.c_str()); - start_time = end_time; - } + SDL_SetRenderDrawColor( + sdlRenderer, (Uint8)(clear_color.x * 0), (Uint8)(clear_color.y * 0), + (Uint8)(clear_color.z * 0), (Uint8)(clear_color.w * 0)); } - // Cleanup + ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData()); + SDL_RenderPresent(sdlRenderer); - if (is_create_connection) { - LeaveConnection(peer_server); + 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 [" + server_signal_status_str + "|" + + client_signal_status_str + "|" + + server_connection_status_str + "|" + + client_connection_status_str + "]"; + // For MacOS, UI frameworks can only be called from the main thread + SDL_SetWindowTitle(window, window_title.c_str()); + start_time = end_time; } + } - if (joined) { - LeaveConnection(peer_client); - } + // Cleanup - rtc_thread.join(); - SDL_CloseAudioDevice(output_dev); - SDL_CloseAudioDevice(input_dev); + if (is_create_connection) { + LeaveConnection(peer_server); + } - mouse_controller->Destroy(); + if (joined) { + LeaveConnection(peer_client); + } - ImGui_ImplSDLRenderer2_Shutdown(); - ImGui_ImplSDL2_Shutdown(); - ImGui::DestroyContext(); + rtc_thread.join(); + SDL_CloseAudioDevice(output_dev); + SDL_CloseAudioDevice(input_dev); - SDL_DestroyRenderer(sdlRenderer); - SDL_DestroyWindow(window); + mouse_controller->Destroy(); - SDL_CloseAudio(); - SDL_Quit(); + ImGui_ImplSDLRenderer2_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + + SDL_DestroyRenderer(sdlRenderer); + SDL_DestroyWindow(window); + + SDL_CloseAudio(); + SDL_Quit(); return 0; } \ No newline at end of file diff --git a/src/screen_capturer/windows/screen_capturer_wgc.cpp b/src/screen_capturer/windows/screen_capturer_wgc.cpp index 994b82c..e8829c1 100644 --- a/src/screen_capturer/windows/screen_capturer_wgc.cpp +++ b/src/screen_capturer/windows/screen_capturer_wgc.cpp @@ -5,36 +5,9 @@ #include #include -extern "C" { -#include -#include -}; - #include -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; -} +#include "libyuv.h" BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, HDC hdc, LPRECT lprc, LPARAM data) { @@ -81,7 +54,11 @@ int ScreenCapturerWgc::Init(const RECORD_DESKTOP_RECT &rect, const int fps, int error = 0; if (_inited == true) return error; - nv12_frame_ = new unsigned char[rect.right * rect.bottom * 4]; + int r = rect.right; + int b = rect.bottom; + + nv12_frame_ = new unsigned char[rect.right * rect.bottom * 3 / 2]; + nv12_frame_scaled_ = new unsigned char[1280 * 720 * 3 / 2]; _fps = fps; @@ -120,6 +97,11 @@ int ScreenCapturerWgc::Destroy() { nv12_frame_ = nullptr; } + if (nv12_frame_scaled_) { + delete nv12_frame_scaled_; + nv12_frame_scaled_ = nullptr; + } + Stop(); CleanUp(); @@ -163,12 +145,83 @@ int ScreenCapturerWgc::Stop() { return 0; } +void ConvertABGRtoBGRA(const uint8_t *abgr_data, uint8_t *bgra_data, int width, + int height, int abgr_stride, int bgra_stride) { + for (int i = 0; i < height; ++i) { + for (int j = 0; j < width; ++j) { + // ABGR到BGRA的索引映射 + int abgr_index = (i * abgr_stride + j) * 4; + int bgra_index = (i * bgra_stride + j) * 4; + + // 直接交换蓝色和红色分量,同时保持Alpha通道不变 + bgra_data[bgra_index + 0] = abgr_data[abgr_index + 2]; // 蓝色 + bgra_data[bgra_index + 1] = abgr_data[abgr_index + 1]; // 绿色 + bgra_data[bgra_index + 2] = abgr_data[abgr_index + 0]; // 红色 + bgra_data[bgra_index + 3] = abgr_data[abgr_index + 3]; // Alpha + } + } +} + +void ConvertBGRAtoABGR(const uint8_t *bgra_data, uint8_t *abgr_data, int width, + int height, int bgra_stride, int abgr_stride) { + for (int i = 0; i < height; ++i) { + for (int j = 0; j < width; ++j) { + // BGRA到ABGR的索引映射 + int bgra_index = (i * bgra_stride + j) * 4; + int abgr_index = (i * abgr_stride + j) * 4; + + // 交换红色和蓝色分量,同时保持Alpha通道在最前面 + abgr_data[abgr_index + 0] = bgra_data[bgra_index + 3]; // Alpha + abgr_data[abgr_index + 1] = bgra_data[bgra_index + 0]; // Blue + abgr_data[abgr_index + 2] = bgra_data[bgra_index + 1]; // Green + abgr_data[abgr_index + 3] = bgra_data[bgra_index + 2]; // Red + } + } +} + void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame &frame) { - if (_on_data) - BGRAToNV12FFmpeg((unsigned char *)frame.data, frame.width, frame.height, - nv12_frame_); - _on_data(nv12_frame_, frame.width * frame.height * 3 / 2, frame.width, - frame.height); + if (_on_data) { + int width = 1280; + int height = 720; + + // libyuv::ARGBToI420(frame.data, frame.width * 4, yuv420_frame_, + // frame.width, + // yuv420_frame_ + frame.width * frame.height, + // frame.width / 2, + // yuv420_frame_ + frame.width * frame.height * 5 / 4, + // frame.width / 2, frame.width, frame.height); + + // libyuv::I420Scale( + // (const uint8_t *)yuv420_frame_, frame.width, + // (const uint8_t *)(yuv420_frame_ + frame.width * frame.height), + // frame.width / 2, + // (const uint8_t *)(yuv420_frame_ + frame.width * frame.height * 5 / + // 4), frame.width / 2, frame.width, frame.height, (uint8_t + // *)yuv420_frame_, width, (uint8_t *)(yuv420_frame_ + width * height), + // width / 2, (uint8_t *)(yuv420_frame_ + width * height * 5 / 4), width + // / 2, width, height, libyuv::FilterMode::kFilterLinear); + + // libyuv::I420ToNV12( + // (const uint8_t *)yuv420_frame_, width, + // (const uint8_t *)(yuv420_frame_ + width * height), width / 2, + // (const uint8_t *)(yuv420_frame_ + width * height * 5 / 4), width / 2, + // nv12_frame_, width, nv12_frame_ + width * height, width, width, + // height); + + libyuv::ARGBToNV12(frame.data, frame.width * 4, nv12_frame_, frame.width, + nv12_frame_ + frame.width * frame.height, + frame.width / 2, frame.width, frame.height); + + libyuv::NV12Scale( + (const uint8_t *)nv12_frame_, frame.width, + (const uint8_t *)(nv12_frame_ + frame.width * frame.height), + frame.width / 2, frame.width, frame.height, + (uint8_t *)nv12_frame_scaled_, width, + (uint8_t *)(nv12_frame_scaled_ + width * height), width / 2, width, + height, libyuv::FilterMode::kFilterLinear); + + _on_data(nv12_frame_scaled_, width * height * 3 / 2, width, height); + } } void ScreenCapturerWgc::CleanUp() { diff --git a/src/screen_capturer/windows/screen_capturer_wgc.h b/src/screen_capturer/windows/screen_capturer_wgc.h index 21b9c13..c6e7f45 100644 --- a/src/screen_capturer/windows/screen_capturer_wgc.h +++ b/src/screen_capturer/windows/screen_capturer_wgc.h @@ -49,9 +49,10 @@ class ScreenCapturerWgc : public ScreenCapturer, int _fps; - cb_desktop_data _on_data; + cb_desktop_data _on_data = nullptr; unsigned char *nv12_frame_ = nullptr; + unsigned char *nv12_frame_scaled_ = nullptr; }; #endif \ No newline at end of file diff --git a/thirdparty/projectx b/thirdparty/projectx index 6df90ff..57ff14a 160000 --- a/thirdparty/projectx +++ b/thirdparty/projectx @@ -1 +1 @@ -Subproject commit 6df90ff55ae6e63ee6f096993ca08d3bf768edca +Subproject commit 57ff14ada44f2d883b1066fc56e3a42e8e29dfa4 diff --git a/xmake.lua b/xmake.lua index c2d470b..afd3d21 100644 --- a/xmake.lua +++ b/xmake.lua @@ -16,28 +16,22 @@ end add_requires("sdl2 2.28.3", {system = false}) add_requires("spdlog 1.11.0", {system = false}) add_requires("imgui 1.89.9", {configs = {sdl2 = true, sdl2_renderer = true}}) +add_requires("libyuv") if is_os("windows") then add_links("Shell32", "windowsapp", "dwmapi", "User32", "kernel32", "SDL2-static", "SDL2main", "gdi32", "winmm", "setupapi", "version", "Imm32", "iphlpapi") - add_requires("vcpkg::ffmpeg 5.1.2", {configs = {shared = false}}) - add_packages("vcpkg::ffmpeg") elseif is_os("linux") then - add_requires("ffmpeg 5.1.2", {system = false}) - add_packages("ffmpeg") add_syslinks("pthread", "dl") add_linkdirs("thirdparty/projectx/thirdparty/nvcodec/Lib/x64") add_links("SDL2", "cuda", "nvidia-encode", "nvcuvid") - add_ldflags("-lavformat", "-lavdevice", "-lavfilter", "-lavcodec", - "-lswscale", "-lavutil", "-lswresample", - "-lasound", "-lxcb-shape", "-lxcb-xfixes", "-lsndio", "-lxcb", + add_ldflags("-lasound", "-lxcb-shape", "-lxcb-xfixes", "-lsndio", "-lxcb", "-lxcb-shm", "-lXext", "-lX11", "-lXv", "-ldl", "-lpthread", {force = true}) elseif is_os("macosx") then - add_requires("ffmpeg 5.1.2", {system = false}) add_requires("libxcb", {system = false}) - add_packages("ffmpeg", "libxcb") + add_packages("libxcb") add_links("SDL2", "SDL2main") add_ldflags("-Wl,-ld_classic") add_frameworks("OpenGL") @@ -62,6 +56,7 @@ target("common") target("screen_capturer") set_kind("object") add_deps("log") + add_packages("libyuv") add_includedirs("src/screen_capturer", {public = true}) if is_os("windows") then add_files("src/screen_capturer/windows/*.cpp")