mirror of
				https://github.com/kunkundi/crossdesk.git
				synced 2025-10-28 11:52:32 +08:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			b2ab940f20
			...
			win-virtua
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 288bb96e0c | 
| @@ -44,9 +44,6 @@ int ConfigCenter::Load() { | ||||
|   enable_self_hosted_ = | ||||
|       ini_.GetBoolValue(section_, "enable_self_hosted", enable_self_hosted_); | ||||
|  | ||||
|   enable_minimize_to_tray_ = ini_.GetBoolValue( | ||||
|       section_, "enable_minimize_to_tray", enable_minimize_to_tray_); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| @@ -65,8 +62,6 @@ int ConfigCenter::Save() { | ||||
|   ini_.SetLongValue(section_, "server_port", static_cast<long>(server_port_)); | ||||
|   ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str()); | ||||
|   ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_); | ||||
|   ini_.SetBoolValue(section_, "enable_minimize_to_tray", | ||||
|                     enable_minimize_to_tray_); | ||||
|  | ||||
|   SI_Error rc = ini_.SaveFile(config_path_.c_str()); | ||||
|   if (rc < 0) { | ||||
| @@ -191,11 +186,6 @@ int ConfigCenter::SetSelfHosted(bool enable_self_hosted) { | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int ConfigCenter::SetMinimizeToTray(bool enable_minimize_to_tray) { | ||||
|   enable_minimize_to_tray_ = enable_minimize_to_tray; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // getters | ||||
|  | ||||
| ConfigCenter::LANGUAGE ConfigCenter::GetLanguage() const { return language_; } | ||||
| @@ -236,6 +226,4 @@ std::string ConfigCenter::GetDefaultCertFilePath() const { | ||||
|   return cert_file_path_default_; | ||||
| } | ||||
|  | ||||
| bool ConfigCenter::IsSelfHosted() const { return enable_self_hosted_; } | ||||
|  | ||||
| bool ConfigCenter::IsMinimizeToTray() const { return enable_minimize_to_tray_; } | ||||
| bool ConfigCenter::IsSelfHosted() const { return enable_self_hosted_; } | ||||
| @@ -36,7 +36,6 @@ class ConfigCenter { | ||||
|   int SetServerPort(int server_port); | ||||
|   int SetCertFilePath(const std::string& cert_file_path); | ||||
|   int SetSelfHosted(bool enable_self_hosted); | ||||
|   int SetMinimizeToTray(bool enable_minimize_to_tray); | ||||
|  | ||||
|   // read config | ||||
|  | ||||
| @@ -54,7 +53,6 @@ class ConfigCenter { | ||||
|   int GetDefaultServerPort() const; | ||||
|   std::string GetDefaultCertFilePath() const; | ||||
|   bool IsSelfHosted() const; | ||||
|   bool IsMinimizeToTray() const; | ||||
|  | ||||
|   int Load(); | ||||
|   int Save(); | ||||
| @@ -78,7 +76,6 @@ class ConfigCenter { | ||||
|   int server_port_default_ = 9099; | ||||
|   std::string cert_file_path_default_ = ""; | ||||
|   bool enable_self_hosted_ = false; | ||||
|   bool enable_minimize_to_tray_ = false; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -20,8 +20,8 @@ | ||||
| #define INPUT_WINDOW_PADDING_EN 96 | ||||
| #define SETTINGS_WINDOW_WIDTH_CN 202 | ||||
| #define SETTINGS_WINDOW_WIDTH_EN 248 | ||||
| #define SETTINGS_WINDOW_HEIGHT_CN 345 | ||||
| #define SETTINGS_WINDOW_HEIGHT_EN 345 | ||||
| #define SETTINGS_WINDOW_HEIGHT_CN 315 | ||||
| #define SETTINGS_WINDOW_HEIGHT_EN 315 | ||||
| #define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_CN 228 | ||||
| #define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_EN 275 | ||||
| #define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_CN 165 | ||||
| @@ -42,8 +42,6 @@ | ||||
| #define ENABLE_SRTP_CHECKBOX_PADDING_EN 218 | ||||
| #define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_CN 171 | ||||
| #define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_EN 218 | ||||
| #define ENABLE_MINIZE_TO_TRAY_PADDING_CN 171 | ||||
| #define ENABLE_MINIZE_TO_TRAY_PADDING_EN 218 | ||||
| #define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_CN 90 | ||||
| #define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_EN 137 | ||||
| #define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN 90 | ||||
|   | ||||
| @@ -8,10 +8,6 @@ | ||||
|  | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| #if _WIN32 | ||||
| #include <Windows.h> | ||||
| #endif | ||||
| namespace localization { | ||||
|  | ||||
| static std::vector<std::string> local_desktop = { | ||||
| @@ -159,12 +155,6 @@ static std::vector<std::string> version = { | ||||
| static std::vector<std::string> confirm_delete_connection = { | ||||
|     reinterpret_cast<const char*>(u8"确认删除此连接"), | ||||
|     "Confirm to delete this connection"}; | ||||
| #if _WIN32 | ||||
|  | ||||
| static std::vector<std::string> minimize_to_tray = { | ||||
|     reinterpret_cast<const char*>(u8"退出时最小化到系统托盘:"), | ||||
|     "Minimize to system tray when exit:"}; | ||||
| static std::vector<LPCWSTR> exit_program = {L"退出", L"Exit"}; | ||||
| #endif | ||||
| }  // namespace localization | ||||
|  | ||||
| #endif | ||||
| @@ -588,17 +588,6 @@ int Render::CreateMainWindow() { | ||||
|   // for window region action | ||||
|   SDL_SetWindowHitTest(main_window_, HitTestCallback, this); | ||||
|  | ||||
| #if _WIN32 | ||||
|   SDL_PropertiesID props = SDL_GetWindowProperties(main_window_); | ||||
|   HWND main_hwnd = (HWND)SDL_GetPointerProperty( | ||||
|       props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); | ||||
|  | ||||
|   HICON tray_icon = (HICON)LoadImageW(NULL, L"crossdesk.ico", IMAGE_ICON, 0, 0, | ||||
|                                       LR_LOADFROMFILE | LR_DEFAULTSIZE); | ||||
|   tray_ = std::make_unique<WinTray>(main_hwnd, tray_icon, L"CrossDesk", | ||||
|                                     localization_language_index_); | ||||
| #endif | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| @@ -979,14 +968,6 @@ void Render::MainLoop() { | ||||
|       ProcessSdlEvent(event); | ||||
|     } | ||||
|  | ||||
| #if _WIN32 | ||||
|     MSG msg; | ||||
|     while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { | ||||
|       TranslateMessage(&msg); | ||||
|       DispatchMessage(&msg); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     UpdateLabels(); | ||||
|     HandleRecentConnections(); | ||||
|     HandleStreamWindow(); | ||||
|   | ||||
| @@ -29,9 +29,6 @@ | ||||
| #include "screen_capturer_factory.h" | ||||
| #include "speaker_capturer_factory.h" | ||||
| #include "thumbnail.h" | ||||
| #if _WIN32 | ||||
| #include "win_tray.h" | ||||
| #endif | ||||
|  | ||||
| class Render { | ||||
|  public: | ||||
| @@ -301,9 +298,6 @@ class Render { | ||||
|   ImGuiContext* main_ctx_ = nullptr; | ||||
|   bool exit_ = false; | ||||
|   const int sdl_refresh_ms_ = 16;  // ~60 FPS | ||||
| #if _WIN32 | ||||
|   std::unique_ptr<WinTray> tray_; | ||||
| #endif | ||||
|  | ||||
|   // main window properties | ||||
|   bool start_mouse_controller_ = false; | ||||
| @@ -450,8 +444,6 @@ class Render { | ||||
|   bool enable_hardware_video_codec_last_ = false; | ||||
|   bool enable_turn_last_ = false; | ||||
|   bool enable_srtp_last_ = false; | ||||
|   bool enable_minimize_to_tray_ = false; | ||||
|   bool enable_minimize_to_tray_last_ = false; | ||||
|   char signal_server_ip_tmp_[256] = "api.crossdesk.cn"; | ||||
|   char signal_server_port_tmp_[6] = "9099"; | ||||
|   bool settings_window_pos_reset_ = true; | ||||
|   | ||||
| @@ -139,17 +139,9 @@ int Render::TitleBar(bool main_window) { | ||||
|     float xmark_size = 12.0f; | ||||
|     std::string close_button = "##xmark";  // ICON_FA_XMARK; | ||||
|     if (ImGui::Button(close_button.c_str(), ImVec2(BUTTON_PADDING, 30))) { | ||||
| #if _WIN32 | ||||
|       if (enable_minimize_to_tray_) { | ||||
|         tray_->MinimizeToTray(); | ||||
|       } else { | ||||
| #endif | ||||
|         SDL_Event event; | ||||
|         event.type = SDL_EVENT_QUIT; | ||||
|         SDL_PushEvent(&event); | ||||
| #if _WIN32 | ||||
|       } | ||||
| #endif | ||||
|       SDL_Event event; | ||||
|       event.type = SDL_EVENT_QUIT; | ||||
|       SDL_PushEvent(&event); | ||||
|     } | ||||
|     draw_list->AddLine(ImVec2(xmark_pos_x - xmark_size / 2 - 0.25f, | ||||
|                               xmark_pos_y - xmark_size / 2 + 0.75f), | ||||
|   | ||||
| @@ -1,112 +0,0 @@ | ||||
| #include "win_tray.h" | ||||
|  | ||||
| #include <SDL3/SDL.h> | ||||
|  | ||||
| #include "localization.h" | ||||
|  | ||||
| // callback for the message-only window that handles tray icon messages | ||||
| static LRESULT CALLBACK MsgWndProc(HWND hwnd, UINT msg, WPARAM wParam, | ||||
|                                    LPARAM lParam) { | ||||
|   WinTray* tray = | ||||
|       reinterpret_cast<WinTray*>(GetWindowLongPtr(hwnd, GWLP_USERDATA)); | ||||
|   if (!tray) { | ||||
|     return DefWindowProc(hwnd, msg, wParam, lParam); | ||||
|   } | ||||
|  | ||||
|   if (msg == WM_TRAY_CALLBACK) { | ||||
|     MSG tmpMsg = {}; | ||||
|     tmpMsg.message = msg; | ||||
|     tmpMsg.wParam = wParam; | ||||
|     tmpMsg.lParam = lParam; | ||||
|     tray->HandleTrayMessage(&tmpMsg); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   return DefWindowProc(hwnd, msg, wParam, lParam); | ||||
| } | ||||
|  | ||||
| WinTray::WinTray(HWND app_hwnd, HICON icon, const std::wstring& tooltip, | ||||
|                  int language_index) | ||||
|     : app_hwnd_(app_hwnd), | ||||
|       icon_(icon), | ||||
|       tip_(tooltip), | ||||
|       hwnd_message_only_(nullptr), | ||||
|       language_index_(language_index) { | ||||
|   WNDCLASS wc = {}; | ||||
|   wc.lpfnWndProc = MsgWndProc; | ||||
|   wc.hInstance = GetModuleHandle(nullptr); | ||||
|   wc.lpszClassName = L"TrayMessageWindow"; | ||||
|   RegisterClass(&wc); | ||||
|  | ||||
|   // create a message-only window to receive tray messages | ||||
|   hwnd_message_only_ = | ||||
|       CreateWindowEx(0, wc.lpszClassName, L"TrayMsg", 0, 0, 0, 0, 0, | ||||
|                      HWND_MESSAGE, nullptr, wc.hInstance, nullptr); | ||||
|  | ||||
|   // store pointer to this WinTray instance in window data | ||||
|   SetWindowLongPtr(hwnd_message_only_, GWLP_USERDATA, | ||||
|                    reinterpret_cast<LONG_PTR>(this)); | ||||
|  | ||||
|   // initialize NOTIFYICONDATA structure | ||||
|   ZeroMemory(&nid_, sizeof(nid_)); | ||||
|   nid_.cbSize = sizeof(nid_); | ||||
|   nid_.hWnd = hwnd_message_only_; | ||||
|   nid_.uID = 1; | ||||
|   nid_.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; | ||||
|   nid_.uCallbackMessage = WM_TRAY_CALLBACK; | ||||
|   nid_.hIcon = icon_; | ||||
|   wcsncpy_s(nid_.szTip, tip_.c_str(), _TRUNCATE); | ||||
| } | ||||
|  | ||||
| WinTray::~WinTray() { | ||||
|   RemoveTrayIcon(); | ||||
|   if (hwnd_message_only_) DestroyWindow(hwnd_message_only_); | ||||
| } | ||||
|  | ||||
| void WinTray::MinimizeToTray() { | ||||
|   Shell_NotifyIcon(NIM_ADD, &nid_); | ||||
|   // hide application window | ||||
|   ShowWindow(app_hwnd_, SW_HIDE); | ||||
| } | ||||
|  | ||||
| void WinTray::RemoveTrayIcon() { Shell_NotifyIcon(NIM_DELETE, &nid_); } | ||||
|  | ||||
| bool WinTray::HandleTrayMessage(MSG* msg) { | ||||
|   if (!msg || msg->message != WM_TRAY_CALLBACK) return false; | ||||
|  | ||||
|   switch (LOWORD(msg->lParam)) { | ||||
|     case WM_LBUTTONDBLCLK: | ||||
|     case WM_LBUTTONUP: { | ||||
|       ShowWindow(app_hwnd_, SW_SHOW); | ||||
|       SetForegroundWindow(app_hwnd_); | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     case WM_RBUTTONUP: { | ||||
|       POINT pt; | ||||
|       GetCursorPos(&pt); | ||||
|       HMENU menu = CreatePopupMenu(); | ||||
|       AppendMenuW(menu, MF_STRING, 1001, | ||||
|                   localization::exit_program[language_index_]); | ||||
|  | ||||
|       SetForegroundWindow(hwnd_message_only_); | ||||
|       int cmd = | ||||
|           TrackPopupMenu(menu, TPM_RETURNCMD | TPM_NONOTIFY | TPM_LEFTALIGN, | ||||
|                          pt.x, pt.y, 0, hwnd_message_only_, nullptr); | ||||
|       DestroyMenu(menu); | ||||
|  | ||||
|       // handle menu command | ||||
|       if (cmd == 1001) { | ||||
|         // exit application | ||||
|         SDL_Event event; | ||||
|         event.type = SDL_EVENT_QUIT; | ||||
|         SDL_PushEvent(&event); | ||||
|       } else if (cmd == 1002) { | ||||
|         ShowWindow(app_hwnd_, SW_SHOW);  // show main window | ||||
|         SetForegroundWindow(app_hwnd_); | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
| @@ -1,36 +0,0 @@ | ||||
| /* | ||||
|  * @Author: DI JUNKUN | ||||
|  * @Date: 2025-10-22 | ||||
|  * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. | ||||
|  */ | ||||
|  | ||||
| #ifndef _WIN_TRAY_H_ | ||||
| #define _WIN_TRAY_H_ | ||||
|  | ||||
| #include <Windows.h> | ||||
| #include <shellapi.h> | ||||
|  | ||||
| #include <string> | ||||
|  | ||||
| #define WM_TRAY_CALLBACK (WM_USER + 1) | ||||
|  | ||||
| class WinTray { | ||||
|  public: | ||||
|   WinTray(HWND app_hwnd, HICON icon, const std::wstring& tooltip, | ||||
|           int language_index); | ||||
|   ~WinTray(); | ||||
|  | ||||
|   void MinimizeToTray(); | ||||
|   void RemoveTrayIcon(); | ||||
|   bool HandleTrayMessage(MSG* msg); | ||||
|  | ||||
|  private: | ||||
|   HWND app_hwnd_; | ||||
|   HWND hwnd_message_only_; | ||||
|   HICON icon_; | ||||
|   std::wstring tip_; | ||||
|   int language_index_; | ||||
|   NOTIFYICONDATA nid_; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| @@ -57,7 +57,7 @@ int Render::SettingWindow() { | ||||
|             localization::language_en[localization_language_index_].c_str()}; | ||||
|  | ||||
|         settings_items_offset += settings_items_padding; | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 4); | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 2); | ||||
|         ImGui::Text( | ||||
|             "%s", localization::language[localization_language_index_].c_str()); | ||||
|         if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { | ||||
| @@ -88,7 +88,7 @@ int Render::SettingWindow() { | ||||
|                 .c_str()}; | ||||
|  | ||||
|         settings_items_offset += settings_items_padding; | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 4); | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 2); | ||||
|         ImGui::Text( | ||||
|             "%s", | ||||
|             localization::video_quality[localization_language_index_].c_str()); | ||||
| @@ -111,7 +111,7 @@ int Render::SettingWindow() { | ||||
|         const char* video_frame_rate_items[] = {"30 fps", "60 fps"}; | ||||
|  | ||||
|         settings_items_offset += settings_items_padding; | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 4); | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 2); | ||||
|         ImGui::Text("%s", | ||||
|                     localization::video_frame_rate[localization_language_index_] | ||||
|                         .c_str()); | ||||
| @@ -137,7 +137,7 @@ int Render::SettingWindow() { | ||||
|             localization::av1[localization_language_index_].c_str()}; | ||||
|  | ||||
|         settings_items_offset += settings_items_padding; | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 4); | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 2); | ||||
|         ImGui::Text( | ||||
|             "%s", | ||||
|             localization::video_encode_format[localization_language_index_] | ||||
| @@ -160,7 +160,7 @@ int Render::SettingWindow() { | ||||
|  | ||||
|       { | ||||
|         settings_items_offset += settings_items_padding; | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 4); | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 2); | ||||
|         ImGui::Text("%s", localization::enable_hardware_video_codec | ||||
|                               [localization_language_index_] | ||||
|                                   .c_str()); | ||||
| @@ -179,7 +179,7 @@ int Render::SettingWindow() { | ||||
|  | ||||
|       { | ||||
|         settings_items_offset += settings_items_padding; | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 4); | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 2); | ||||
|         ImGui::Text( | ||||
|             "%s", | ||||
|             localization::enable_turn[localization_language_index_].c_str()); | ||||
| @@ -197,7 +197,7 @@ int Render::SettingWindow() { | ||||
|  | ||||
|       { | ||||
|         settings_items_offset += settings_items_padding; | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 4); | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 2); | ||||
|         ImGui::Text( | ||||
|             "%s", | ||||
|             localization::enable_srtp[localization_language_index_].c_str()); | ||||
| @@ -215,7 +215,7 @@ int Render::SettingWindow() { | ||||
|  | ||||
|       { | ||||
|         settings_items_offset += settings_items_padding; | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 1); | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 2); | ||||
|  | ||||
|         if (ImGui::Button(localization::self_hosted_server_config | ||||
|                               [localization_language_index_] | ||||
| @@ -232,27 +232,7 @@ int Render::SettingWindow() { | ||||
|         ImGui::Checkbox("##enable_self_hosted_server", | ||||
|                         &enable_self_hosted_server_); | ||||
|       } | ||||
| #if _WIN32 | ||||
|       ImGui::Separator(); | ||||
|  | ||||
|       { | ||||
|         settings_items_offset += settings_items_padding; | ||||
|         ImGui::SetCursorPosY(settings_items_offset + 4); | ||||
|  | ||||
|         ImGui::Text("%s", | ||||
|                     localization::minimize_to_tray[localization_language_index_] | ||||
|                         .c_str()); | ||||
|  | ||||
|         if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { | ||||
|           ImGui::SetCursorPosX(ENABLE_MINIZE_TO_TRAY_PADDING_CN); | ||||
|         } else { | ||||
|           ImGui::SetCursorPosX(ENABLE_MINIZE_TO_TRAY_PADDING_EN); | ||||
|         } | ||||
|         ImGui::SetCursorPosY(settings_items_offset); | ||||
|         ImGui::Checkbox("##enable_minimize_to_tray_", | ||||
|                         &enable_minimize_to_tray_); | ||||
|       } | ||||
| #endif | ||||
|       if (stream_window_inited_) { | ||||
|         ImGui::EndDisabled(); | ||||
|       } | ||||
|   | ||||
| @@ -43,12 +43,7 @@ int Render::ShowSimpleFileBrowser() { | ||||
|         localization::select_a_file[localization_language_index_].c_str(); | ||||
|   } | ||||
|  | ||||
|   // 设置固定宽度 | ||||
|   // ImGui::SetNextItemWidth(SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH); | ||||
|  | ||||
|   ImGui::PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);  // 禁用自动关闭 | ||||
|   if (ImGui::BeginCombo("##select_a_file", display_text.c_str())) { | ||||
|     bool file_selected = false; | ||||
|     if (selected_current_file_path_ == "Root" || | ||||
|         !std::filesystem::exists(selected_current_file_path_) || | ||||
|         !std::filesystem::is_directory(selected_current_file_path_)) { | ||||
| @@ -82,7 +77,6 @@ int Render::ShowSimpleFileBrowser() { | ||||
|           } else { | ||||
|             if (ImGui::Selectable(name.c_str())) { | ||||
|               selected_file_ = entry.path().string(); | ||||
|               file_selected = true;  // 记录选中文件 | ||||
|             } | ||||
|           } | ||||
|         } | ||||
| @@ -91,14 +85,8 @@ int Render::ShowSimpleFileBrowser() { | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // 如果选中了文件,则自动关闭下拉框 | ||||
|     if (file_selected) { | ||||
|       ImGui::EndCombo();  // 关闭下拉框 | ||||
|     } else { | ||||
|       ImGui::EndCombo();  // 保持下拉框开启 | ||||
|     } | ||||
|     ImGui::EndCombo(); | ||||
|   } | ||||
|   ImGui::PopItemFlag();  // 恢复默认行为 | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| 
 | ||||
| static std::vector<DisplayInfo> gs_display_list; | ||||
| 
 | ||||
| std::string WideToUtf8(const wchar_t *wideStr) { | ||||
| std::string WideToUtf8(const wchar_t* wideStr) { | ||||
|   int size_needed = WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, nullptr, 0, | ||||
|                                         nullptr, nullptr); | ||||
|   std::string result(size_needed, 0); | ||||
| @@ -31,14 +31,14 @@ BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, [[maybe_unused]] HDC hdc, | ||||
|     if (monitor_info_.dwFlags & MONITORINFOF_PRIMARY) { | ||||
|       gs_display_list.insert( | ||||
|           gs_display_list.begin(), | ||||
|           {(void *)hmonitor, WideToUtf8(monitor_info_.szDevice), | ||||
|           {(void*)hmonitor, WideToUtf8(monitor_info_.szDevice), | ||||
|            (monitor_info_.dwFlags & MONITORINFOF_PRIMARY) ? true : false, | ||||
|            monitor_info_.rcMonitor.left, monitor_info_.rcMonitor.top, | ||||
|            monitor_info_.rcMonitor.right, monitor_info_.rcMonitor.bottom}); | ||||
|       *(HMONITOR *)data = hmonitor; | ||||
|       *(HMONITOR*)data = hmonitor; | ||||
|     } else { | ||||
|       gs_display_list.push_back(DisplayInfo( | ||||
|           (void *)hmonitor, WideToUtf8(monitor_info_.szDevice), | ||||
|           (void*)hmonitor, WideToUtf8(monitor_info_.szDevice), | ||||
|           (monitor_info_.dwFlags & MONITORINFOF_PRIMARY) ? true : false, | ||||
|           monitor_info_.rcMonitor.left, monitor_info_.rcMonitor.top, | ||||
|           monitor_info_.rcMonitor.right, monitor_info_.rcMonitor.bottom)); | ||||
| @@ -81,7 +81,7 @@ bool ScreenCapturerWgc::IsWgcSupported() { | ||||
|     /* 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 &) { | ||||
|   } catch (const winrt::hresult_error&) { | ||||
|     return false; | ||||
|   } catch (...) { | ||||
|     return false; | ||||
| @@ -115,7 +115,7 @@ int ScreenCapturerWgc::Init(const int fps, cb_desktop_data cb) { | ||||
|   } | ||||
| 
 | ||||
|   for (int i = 0; i < display_info_list_.size(); i++) { | ||||
|     const auto &display = display_info_list_[i]; | ||||
|     const auto& display = display_info_list_[i]; | ||||
|     LOG_INFO( | ||||
|         "index: {}, display name: {}, is primary: {}, bounds: ({}, {}) - " | ||||
|         "({}, {})", | ||||
| @@ -243,26 +243,28 @@ int ScreenCapturerWgc::SwitchTo(int monitor_index) { | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame &frame, | ||||
| void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame& frame, | ||||
|                                 int id) { | ||||
|   if (on_data_) { | ||||
|     if (!nv12_frame_) { | ||||
|       nv12_frame_ = new unsigned char[frame.width * frame.height * 3 / 2]; | ||||
|     } | ||||
| 
 | ||||
|     libyuv::ARGBToNV12((const uint8_t *)frame.data, frame.width * 4, | ||||
|                        (uint8_t *)nv12_frame_, frame.width, | ||||
|                        (uint8_t *)(nv12_frame_ + frame.width * frame.height), | ||||
|                        frame.width, frame.width, frame.height); | ||||
| 
 | ||||
|     on_data_(nv12_frame_, frame.width * frame.height * 3 / 2, frame.width, | ||||
|              frame.height, display_info_list_[id].name.c_str()); | ||||
|   if (!on_data_) { | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   if (!nv12_frame_) { | ||||
|     nv12_frame_ = new unsigned char[frame.width * frame.height * 3 / 2]; | ||||
|   } | ||||
| 
 | ||||
|   libyuv::ARGBToNV12((const uint8_t*)frame.data, frame.width * 4, | ||||
|                      (uint8_t*)nv12_frame_, frame.width, | ||||
|                      (uint8_t*)(nv12_frame_ + frame.width * frame.height), | ||||
|                      frame.width, frame.width, frame.height); | ||||
| 
 | ||||
|   on_data_(nv12_frame_, frame.width * frame.height * 3 / 2, frame.width, | ||||
|            frame.height, display_info_list_[id].name.c_str()); | ||||
| } | ||||
| 
 | ||||
| void ScreenCapturerWgc::CleanUp() { | ||||
|   if (inited_) { | ||||
|     for (auto &session : sessions_) { | ||||
|     for (auto& session : sessions_) { | ||||
|       if (session.session_) { | ||||
|         session.session_->Stop(); | ||||
|       } | ||||
| @@ -43,6 +43,8 @@ class ScreenCapturerWgc : public ScreenCapturer, | ||||
|   std::vector<DisplayInfo> display_info_list_; | ||||
|   int monitor_index_ = 0; | ||||
|  | ||||
|   HWND hwnd_ = nullptr; | ||||
|  | ||||
|  private: | ||||
|   class WgcSessionInfo { | ||||
|    public: | ||||
| @@ -63,6 +65,9 @@ class ScreenCapturerWgc : public ScreenCapturer, | ||||
|  | ||||
|   unsigned char* nv12_frame_ = nullptr; | ||||
|   unsigned char* nv12_frame_scaled_ = nullptr; | ||||
|  | ||||
|  private: | ||||
|   bool CreateHiddenWindow(); | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										68
									
								
								src/screen_capturer/windows/screen_capturer_wgc.h.bak
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/screen_capturer/windows/screen_capturer_wgc.h.bak
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| #ifndef _SCREEN_CAPTURER_WGC_H_ | ||||
| #define _SCREEN_CAPTURER_WGC_H_ | ||||
|  | ||||
| #include <atomic> | ||||
| #include <functional> | ||||
| #include <string> | ||||
| #include <thread> | ||||
| #include <vector> | ||||
|  | ||||
| #include "screen_capturer.h" | ||||
| #include "wgc_session.h" | ||||
| #include "wgc_session_impl.h" | ||||
|  | ||||
| class ScreenCapturerWgc : public ScreenCapturer, | ||||
|                           public WgcSession::wgc_session_observer { | ||||
|  public: | ||||
|   ScreenCapturerWgc(); | ||||
|   ~ScreenCapturerWgc(); | ||||
|  | ||||
|  public: | ||||
|   bool IsWgcSupported(); | ||||
|  | ||||
|   int Init(const int fps, cb_desktop_data cb) override; | ||||
|   int Destroy() override; | ||||
|   int Start() override; | ||||
|   int Stop() override; | ||||
|  | ||||
|   int Pause(int monitor_index) override; | ||||
|   int Resume(int monitor_index) override; | ||||
|  | ||||
|   std::vector<DisplayInfo> GetDisplayInfoList() { return display_info_list_; } | ||||
|  | ||||
|   int SwitchTo(int monitor_index); | ||||
|  | ||||
|   void OnFrame(const WgcSession::wgc_session_frame& frame, int id); | ||||
|  | ||||
|  protected: | ||||
|   void CleanUp(); | ||||
|  | ||||
|  private: | ||||
|   HMONITOR monitor_; | ||||
|   MONITORINFOEX monitor_info_; | ||||
|   std::vector<DisplayInfo> display_info_list_; | ||||
|   int monitor_index_ = 0; | ||||
|  | ||||
|  private: | ||||
|   class WgcSessionInfo { | ||||
|    public: | ||||
|     std::unique_ptr<WgcSession> session_; | ||||
|     bool inited_ = false; | ||||
|     bool running_ = false; | ||||
|     bool paused_ = false; | ||||
|   }; | ||||
|  | ||||
|   std::vector<WgcSessionInfo> sessions_; | ||||
|  | ||||
|   std::atomic_bool running_; | ||||
|   std::atomic_bool inited_; | ||||
|  | ||||
|   int fps_ = 60; | ||||
|  | ||||
|   cb_desktop_data on_data_ = nullptr; | ||||
|  | ||||
|   unsigned char* nv12_frame_ = nullptr; | ||||
|   unsigned char* nv12_frame_scaled_ = nullptr; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										187
									
								
								src/screen_capturer/windows/screen_capturer_wgc_warp.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/screen_capturer/windows/screen_capturer_wgc_warp.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,187 @@ | ||||
| #include <Windows.h> | ||||
| #include <d3d11_4.h> | ||||
|  | ||||
| #include <iostream> | ||||
| #include <thread> | ||||
|  | ||||
| #include "libyuv.h" | ||||
| #include "rd_log.h" | ||||
| #include "screen_capturer_wgc.h" | ||||
|  | ||||
| // Dummy window proc for hidden window | ||||
| static LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, | ||||
|                                      LPARAM lParam) { | ||||
|   return DefWindowProc(hwnd, msg, wParam, lParam); | ||||
| } | ||||
|  | ||||
| // ======================= 构造函数 / 析构函数 ======================= | ||||
| ScreenCapturerWgc::ScreenCapturerWgc() | ||||
|     : monitor_(nullptr), | ||||
|       hwnd_(nullptr), | ||||
|       monitor_index_(0), | ||||
|       running_(false), | ||||
|       inited_(false), | ||||
|       fps_(60), | ||||
|       on_data_(nullptr), | ||||
|       nv12_frame_(nullptr), | ||||
|       nv12_frame_scaled_(nullptr) {} | ||||
|  | ||||
| ScreenCapturerWgc::~ScreenCapturerWgc() { | ||||
|   Stop(); | ||||
|   CleanUp(); | ||||
|  | ||||
|   if (nv12_frame_) { | ||||
|     delete[] nv12_frame_; | ||||
|     nv12_frame_ = nullptr; | ||||
|   } | ||||
|  | ||||
|   if (nv12_frame_scaled_) { | ||||
|     delete[] nv12_frame_scaled_; | ||||
|     nv12_frame_scaled_ = nullptr; | ||||
|   } | ||||
| } | ||||
|  | ||||
| // ======================= 隐藏窗口创建 ======================= | ||||
| bool ScreenCapturerWgc::CreateHiddenWindow() { | ||||
|   const wchar_t kClassName[] = L"ScreenCapturerHiddenWindow"; | ||||
|  | ||||
|   WNDCLASSW wc = {}; | ||||
|   wc.lpfnWndProc = DummyWndProc; | ||||
|   wc.hInstance = GetModuleHandle(nullptr); | ||||
|   wc.lpszClassName = kClassName; | ||||
|  | ||||
|   if (!RegisterClassW(&wc)) { | ||||
|     std::cerr << "Failed to register dummy window class\n"; | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   hwnd_ = CreateWindowW(kClassName, L"", WS_OVERLAPPEDWINDOW, 0, 0, 1, 1, | ||||
|                         nullptr, nullptr, wc.hInstance, nullptr); | ||||
|   if (!hwnd_) { | ||||
|     std::cerr << "Failed to create dummy window\n"; | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   ShowWindow(hwnd_, SW_HIDE); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| // ======================= 初始化 ======================= | ||||
| int ScreenCapturerWgc::Init(const int fps, cb_desktop_data cb) { | ||||
|   if (inited_) return 0; | ||||
|  | ||||
|   fps_ = fps; | ||||
|   on_data_ = cb; | ||||
|  | ||||
|   // 创建隐藏窗口 | ||||
|   if (!CreateHiddenWindow()) { | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   // 初始化 WGC Session | ||||
|   sessions_.push_back( | ||||
|       {std::make_unique<WgcSessionImpl>(0), false, false, false}); | ||||
|   sessions_.back().session_->RegisterObserver(this); | ||||
|   int error = sessions_.back().session_->Initialize(hwnd_); | ||||
|   if (error != 0) { | ||||
|     std::cerr << "WGC session init failed\n"; | ||||
|     return error; | ||||
|   } | ||||
|   sessions_[0].inited_ = true; | ||||
|  | ||||
|   inited_ = true; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int ScreenCapturerWgc::Destroy() { | ||||
|   Stop(); | ||||
|   CleanUp(); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int ScreenCapturerWgc::Pause(int monitor_index) { | ||||
|   // 目前只支持隐藏窗口,所以忽略 monitor_index | ||||
|   if (!running_) return -1; | ||||
|   sessions_[0].session_->Pause(); | ||||
|   sessions_[0].paused_ = true; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int ScreenCapturerWgc::Resume(int monitor_index) { | ||||
|   if (!running_) return -1; | ||||
|   sessions_[0].session_->Resume(); | ||||
|   sessions_[0].paused_ = false; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int ScreenCapturerWgc::SwitchTo(int monitor_index) { | ||||
|   // 单隐藏窗口模式,不支持切换 | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // ======================= 开始 ======================= | ||||
| int ScreenCapturerWgc::Start() { | ||||
|   if (!inited_) return -1; | ||||
|   if (running_) return 0; | ||||
|   if (sessions_.empty()) return -1; | ||||
|  | ||||
|   sessions_[0].session_->Start(); | ||||
|   sessions_[0].running_ = true; | ||||
|   running_ = true; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // ======================= 停止 ======================= | ||||
| int ScreenCapturerWgc::Stop() { | ||||
|   if (!running_) return 0; | ||||
|  | ||||
|   if (!sessions_.empty()) { | ||||
|     sessions_[0].session_->Stop(); | ||||
|     sessions_[0].running_ = false; | ||||
|   } | ||||
|  | ||||
|   running_ = false; | ||||
|  | ||||
|   if (hwnd_) { | ||||
|     DestroyWindow(hwnd_); | ||||
|     hwnd_ = nullptr; | ||||
|   } | ||||
|  | ||||
|   inited_ = false; | ||||
|   sessions_.clear(); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // ======================= 帧回调 ======================= | ||||
| void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame& frame, | ||||
|                                 int id) { | ||||
|   if (!on_data_) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (!nv12_frame_) { | ||||
|     nv12_frame_ = new unsigned char[frame.width * frame.height * 3 / 2]; | ||||
|   } | ||||
|  | ||||
|   libyuv::ARGBToNV12((const uint8_t*)frame.data, frame.width * 4, | ||||
|                      (uint8_t*)nv12_frame_, frame.width, | ||||
|                      (uint8_t*)(nv12_frame_ + frame.width * frame.height), | ||||
|                      frame.width, frame.width, frame.height); | ||||
|  | ||||
|   on_data_(nv12_frame_, frame.width * frame.height * 3 / 2, frame.width, | ||||
|            frame.height, "hidden_window"); | ||||
| } | ||||
|  | ||||
| // ======================= 清理 ======================= | ||||
| void ScreenCapturerWgc::CleanUp() { | ||||
|   if (inited_) { | ||||
|     for (auto& session : sessions_) { | ||||
|       if (session.session_) { | ||||
|         session.session_->Stop(); | ||||
|       } | ||||
|     } | ||||
|     sessions_.clear(); | ||||
|   } | ||||
| } | ||||
| @@ -7,6 +7,8 @@ | ||||
| #include <iostream> | ||||
| #include <memory> | ||||
|  | ||||
| #include "rd_log.h" | ||||
|  | ||||
| #define CHECK_INIT                            \ | ||||
|   if (!is_initialized_) {                     \ | ||||
|     std::cout << "AE_NEED_INIT" << std::endl; \ | ||||
| @@ -20,122 +22,118 @@ | ||||
|  | ||||
| extern "C" { | ||||
| HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice( | ||||
|     ::IDXGIDevice *dxgiDevice, ::IInspectable **graphicsDevice); | ||||
|     ::IDXGIDevice* dxgiDevice, ::IInspectable** graphicsDevice); | ||||
| } | ||||
|  | ||||
| WgcSessionImpl::WgcSessionImpl(int id) : id_(id) {} | ||||
|  | ||||
| WgcSessionImpl::~WgcSessionImpl() { | ||||
|   Stop(); | ||||
|   CleanUp(); | ||||
|   try { | ||||
|     Stop(); | ||||
|     CleanUp(); | ||||
|   } catch (...) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void WgcSessionImpl::Release() { delete this; } | ||||
|  | ||||
| int WgcSessionImpl::Initialize(HWND hwnd) { | ||||
|   std::lock_guard locker(lock_); | ||||
|  | ||||
|   std::scoped_lock locker(lock_); | ||||
|   target_.hwnd = hwnd; | ||||
|   target_.is_window = true; | ||||
|   return Initialize(); | ||||
| } | ||||
|  | ||||
| int WgcSessionImpl::Initialize(HMONITOR hmonitor) { | ||||
|   std::lock_guard locker(lock_); | ||||
|  | ||||
|   std::scoped_lock locker(lock_); | ||||
|   target_.hmonitor = hmonitor; | ||||
|   target_.is_window = false; | ||||
|   return Initialize(); | ||||
| } | ||||
|  | ||||
| void WgcSessionImpl::RegisterObserver(wgc_session_observer *observer) { | ||||
|   std::lock_guard locker(lock_); | ||||
| void WgcSessionImpl::RegisterObserver(wgc_session_observer* observer) { | ||||
|   std::scoped_lock locker(lock_); | ||||
|   observer_ = observer; | ||||
| } | ||||
|  | ||||
| int WgcSessionImpl::Start() { | ||||
|   std::lock_guard locker(lock_); | ||||
|   std::scoped_lock locker(lock_); | ||||
|   CHECK_INIT; | ||||
|  | ||||
|   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_item_) { | ||||
|       std::cout << "AE_NO_CAPTURE_ITEM" << std::endl; | ||||
|       LOG_ERROR("No capture item"); | ||||
|       return 2; | ||||
|     } | ||||
|  | ||||
|     if (!capture_framepool_) throw std::exception(); | ||||
|     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); | ||||
|  | ||||
|     is_running_ = true; | ||||
|     capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_); | ||||
|     capture_frame_size_ = current_size; | ||||
|  | ||||
|     // 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(); | ||||
|     capture_framepool_trigger_ = capture_framepool_.FrameArrived( | ||||
|         winrt::auto_revoke, {this, &WgcSessionImpl::OnFrame}); | ||||
|     capture_close_trigger_ = capture_item_.Closed( | ||||
|         winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed}); | ||||
|  | ||||
|     capture_session_.IsCursorCaptureEnabled(false); | ||||
|     capture_session_.StartCapture(); | ||||
|  | ||||
|     error = 0; | ||||
|   } catch (winrt::hresult_error) { | ||||
|     std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl; | ||||
|     is_running_ = true; | ||||
|     is_paused_ = false; | ||||
|     return 0; | ||||
|   } catch (winrt::hresult_error const& e) { | ||||
|     LOG_ERROR("Create WGC Capture Failed: {}", winrt::to_string(e.message())); | ||||
|     return 86; | ||||
|   } catch (...) { | ||||
|     return 86; | ||||
|   } | ||||
|  | ||||
|   return error; | ||||
| } | ||||
|  | ||||
| int WgcSessionImpl::Stop() { | ||||
|   std::lock_guard locker(lock_); | ||||
|  | ||||
|   std::scoped_lock locker(lock_); | ||||
|   CHECK_INIT; | ||||
|  | ||||
|   if (!is_running_) return 0; | ||||
|   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; | ||||
|   try { | ||||
|     if (capture_framepool_trigger_) capture_framepool_trigger_.revoke(); | ||||
|     if (capture_close_trigger_) capture_close_trigger_.revoke(); | ||||
|     if (capture_session_) { | ||||
|       capture_session_.Close(); | ||||
|       capture_session_ = nullptr; | ||||
|     } | ||||
|     if (capture_framepool_) { | ||||
|       capture_framepool_.Close(); | ||||
|       capture_framepool_ = nullptr; | ||||
|     } | ||||
|   } catch (...) { | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int WgcSessionImpl::Pause() { | ||||
|   std::lock_guard locker(lock_); | ||||
|  | ||||
|   is_paused_ = true; | ||||
|  | ||||
|   std::scoped_lock locker(lock_); | ||||
|   CHECK_INIT; | ||||
|   is_paused_ = true; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int WgcSessionImpl::Resume() { | ||||
|   std::lock_guard locker(lock_); | ||||
|  | ||||
|   is_paused_ = false; | ||||
|  | ||||
|   std::scoped_lock locker(lock_); | ||||
|   CHECK_INIT; | ||||
|   is_paused_ = false; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| @@ -143,19 +141,15 @@ 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); | ||||
|   hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, | ||||
|                          nullptr, 0, D3D11_SDK_VERSION, d3d_device.put(), | ||||
|                          nullptr, nullptr); | ||||
|  | ||||
|   if (DXGI_ERROR_UNSUPPORTED == hr) { | ||||
|     // change D3D_DRIVER_TYPE | ||||
|     type = D3D_DRIVER_TYPE_WARP; | ||||
|     hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0, | ||||
|                            D3D11_SDK_VERSION, d3d_device.put(), nullptr, | ||||
|                            nullptr); | ||||
|     hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, flags, | ||||
|                            nullptr, 0, D3D11_SDK_VERSION, d3d_device.put(), | ||||
|                            nullptr, nullptr); | ||||
|   } | ||||
|  | ||||
|   winrt::check_hresult(hr); | ||||
| @@ -168,26 +162,28 @@ auto WgcSessionImpl::CreateD3D11Device() { | ||||
| } | ||||
|  | ||||
| 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}; | ||||
|   auto interop_factory = | ||||
|       winrt::get_activation_factory< | ||||
|           winrt::Windows::Graphics::Capture::GraphicsCaptureItem>() | ||||
|           .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))); | ||||
|       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}; | ||||
|   auto interop_factory = | ||||
|       winrt::get_activation_factory< | ||||
|           winrt::Windows::Graphics::Capture::GraphicsCaptureItem>() | ||||
|           .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))); | ||||
|       reinterpret_cast<void**>(winrt::put_abi(item))); | ||||
|   return item; | ||||
| } | ||||
|  | ||||
| @@ -196,13 +192,10 @@ HRESULT WgcSessionImpl::CreateMappedTexture( | ||||
|     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; | ||||
|  | ||||
|   D3D11_TEXTURE2D_DESC map_desc = src_desc; | ||||
|   map_desc.Width = width ? width : src_desc.Width; | ||||
|   map_desc.Height = height ? height : src_desc.Height; | ||||
|   map_desc.Usage = D3D11_USAGE_STAGING; | ||||
|   map_desc.BindFlags = 0; | ||||
|   map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; | ||||
| @@ -216,163 +209,101 @@ HRESULT WgcSessionImpl::CreateMappedTexture( | ||||
| } | ||||
|  | ||||
| void WgcSessionImpl::OnFrame( | ||||
|     winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const &sender, | ||||
|     [[maybe_unused]] winrt::Windows::Foundation::IInspectable const &args) { | ||||
|   std::lock_guard locker(lock_); | ||||
|     winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const& sender, | ||||
|     [[maybe_unused]] winrt::Windows::Foundation::IInspectable const& args) { | ||||
|   if (!is_running_ || is_paused_) return; | ||||
|   std::scoped_lock locker(lock_); | ||||
|  | ||||
|   auto is_new_size = false; | ||||
|   if (!observer_) return; | ||||
|  | ||||
|   { | ||||
|     auto frame = sender.TryGetNextFrame(); | ||||
|     auto frame_size = frame.ContentSize(); | ||||
|   auto frame = sender.TryGetNextFrame(); | ||||
|   if (!frame) return; | ||||
|  | ||||
|     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 | ||||
|     { | ||||
|       if (is_paused_) { | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       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)}, | ||||
|             id_); | ||||
|       } | ||||
|  | ||||
|       d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (is_new_size) { | ||||
|   auto frame_size = frame.ContentSize(); | ||||
|   bool size_changed = (frame_size.Width != capture_frame_size_.Width || | ||||
|                        frame_size.Height != capture_frame_size_.Height); | ||||
|   if (size_changed) { | ||||
|     capture_frame_size_ = frame_size; | ||||
|     capture_framepool_.Recreate(d3d11_direct_device_, | ||||
|                                 winrt::Windows::Graphics::DirectX:: | ||||
|                                     DirectXPixelFormat::B8G8R8A8UIntNormalized, | ||||
|                                 2, capture_frame_size_); | ||||
|   } | ||||
|  | ||||
|   auto frame_surface = | ||||
|       GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface()); | ||||
|  | ||||
|   if (!d3d11_texture_mapped_ || size_changed) | ||||
|     CreateMappedTexture(frame_surface, frame_size.Width, frame_size.Height); | ||||
|  | ||||
|   d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(), | ||||
|                                       frame_surface.get()); | ||||
|  | ||||
|   D3D11_MAPPED_SUBRESOURCE map_result; | ||||
|   HRESULT hr = d3d11_device_context_->Map(d3d11_texture_mapped_.get(), 0, | ||||
|                                           D3D11_MAP_READ, 0, &map_result); | ||||
|   if (SUCCEEDED(hr)) { | ||||
|     wgc_session_frame frame_info{ | ||||
|         static_cast<unsigned int>(frame_size.Width), | ||||
|         static_cast<unsigned int>(frame_size.Height), map_result.RowPitch, | ||||
|         reinterpret_cast<const unsigned char*>(map_result.pData)}; | ||||
|     observer_->OnFrame(frame_info, id_); | ||||
|     d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void WgcSessionImpl::OnClosed( | ||||
|     winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &, | ||||
|     winrt::Windows::Foundation::IInspectable const &) { | ||||
|     winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&, | ||||
|     winrt::Windows::Foundation::IInspectable const&) { | ||||
|   OutputDebugStringW(L"WgcSessionImpl::OnClosed"); | ||||
|   Stop(); | ||||
| } | ||||
|  | ||||
| int WgcSessionImpl::Initialize() { | ||||
|   if (is_initialized_) return 0; | ||||
|  | ||||
|   if (!(d3d11_direct_device_ = CreateD3D11Device())) { | ||||
|   d3d11_direct_device_ = CreateD3D11Device(); | ||||
|   if (!d3d11_direct_device_) { | ||||
|     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); | ||||
|     capture_item_ = target_.is_window | ||||
|                         ? CreateCaptureItemForWindow(target_.hwnd) | ||||
|                         : CreateCaptureItemForMonitor(target_.hmonitor); | ||||
|  | ||||
|     // Set up | ||||
|     auto d3d11_device = | ||||
|     auto d3d_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; | ||||
|     d3d_device->GetImmediateContext(d3d11_device_context_.put()); | ||||
|   } catch (...) { | ||||
|     LOG_ERROR("AE_WGC_CREATE_CAPTURER_FAILED"); | ||||
|     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(); | ||||
|   std::scoped_lock locker(lock_); | ||||
|   if (cleaned_.exchange(true)) return; | ||||
|  | ||||
|   try { | ||||
|     if (capture_framepool_trigger_) capture_framepool_trigger_.revoke(); | ||||
|     if (capture_close_trigger_) capture_close_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; | ||||
|   } catch (...) { | ||||
|   } | ||||
|  | ||||
|   capture_framepool_ = nullptr; | ||||
|   capture_session_ = nullptr; | ||||
|   capture_item_ = nullptr; | ||||
|   d3d11_texture_mapped_ = nullptr; | ||||
|   d3d11_device_context_ = nullptr; | ||||
|   d3d11_direct_device_ = nullptr; | ||||
|  | ||||
|   is_initialized_ = false; | ||||
|   is_running_ = 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_); | ||||
| // } | ||||
							
								
								
									
										380
									
								
								src/screen_capturer/windows/wgc_session_impl.cpp.bak
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								src/screen_capturer/windows/wgc_session_impl.cpp.bak
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,380 @@ | ||||
| #include "wgc_session_impl.h" | ||||
|  | ||||
| #include <Windows.Graphics.Capture.Interop.h> | ||||
|  | ||||
| #include <atomic> | ||||
| #include <functional> | ||||
| #include <iostream> | ||||
| #include <memory> | ||||
|  | ||||
| #include "rd_log.h" | ||||
|  | ||||
| #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(int id) : id_(id) {} | ||||
|  | ||||
| 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(); | ||||
|  | ||||
|     capture_session_.IsCursorCaptureEnabled(false); | ||||
|  | ||||
|     error = 0; | ||||
|   } catch (winrt::hresult_error) { | ||||
|     LOG_ERROR("Create WGC Capture Failed"); | ||||
|     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_); | ||||
|  | ||||
|   is_paused_ = true; | ||||
|  | ||||
|   CHECK_INIT; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int WgcSessionImpl::Resume() { | ||||
|   std::lock_guard locker(lock_); | ||||
|  | ||||
|   is_paused_ = false; | ||||
|  | ||||
|   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 | ||||
|     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, | ||||
|     [[maybe_unused]] 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 | ||||
|     { | ||||
|       if (is_paused_) { | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       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)}, | ||||
|             id_); | ||||
|       } | ||||
|  | ||||
|       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) { | ||||
|     LOG_ERROR("AE_WGC_CREATE_CAPTURER_FAILED"); | ||||
|     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_); | ||||
| // } | ||||
| @@ -146,14 +146,10 @@ target("gui") | ||||
|     add_deps("rd_log", "common", "assets", "config_center", "minirtc",  | ||||
|         "path_manager", "screen_capturer", "speaker_capturer",  | ||||
|         "device_controller", "thumbnail") | ||||
|     add_files("src/gui/*.cpp", "src/gui/panels/*.cpp", "src/gui/toolbars/*.cpp", | ||||
|     add_files("src/gui/*.cpp", "src/gui/panels/*.cpp", "src/gui/toolbars/*.cpp",  | ||||
|         "src/gui/windows/*.cpp") | ||||
|     add_includedirs("src/gui", "src/gui/panels", "src/gui/toolbars", | ||||
|     add_includedirs("src/gui", "src/gui/panels", "src/gui/toolbars",  | ||||
|         "src/gui/windows", {public = true}) | ||||
|     if is_os("windows") then | ||||
|         add_files("src/gui/tray/*.cpp") | ||||
|         add_includedirs("src/gui/tray", {public = true}) | ||||
|     end | ||||
|  | ||||
| target("crossdesk") | ||||
|     set_kind("binary") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user