main.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #include "config.h"
  2. #include "cuda_helper.hpp"
  3. #include "frame_receiver.h"
  4. #include "frame_receiver2.h"
  5. #include "nv12_renderer.h"
  6. #include "third_party/scope_guard.hpp"
  7. #include "video_decoder.h"
  8. #include <imgui.h>
  9. #include <imgui_impl_glfw.h>
  10. #include <imgui_impl_opengl3.h>
  11. #include <glad/gl.h>
  12. #include <GLFW/glfw3.h>
  13. #include <boost/process/child.hpp>
  14. #include <spdlog/spdlog.h>
  15. #include <thread>
  16. #ifdef _MSC_VER
  17. #include <format>
  18. #define fmt std
  19. #endif
  20. // for renderer
  21. int monitor_index = 0;
  22. char *server_address;
  23. uint16_t server_port = 5277;
  24. GLFWwindow *main_window = nullptr;
  25. // for receiver
  26. video_decoder decoder;
  27. void controller_main(const char *this_name) {
  28. // setup imgui context
  29. IMGUI_CHECKVERSION();
  30. ImGui::CreateContext();
  31. auto io = ImGui::GetIO();
  32. io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
  33. ImGui::StyleColorsDark();
  34. ImGui_ImplGlfw_InitForOpenGL(main_window, true);
  35. ImGui_ImplOpenGL3_Init();
  36. static constexpr auto server_address_length = 256;
  37. server_address = (char *) malloc(server_address_length);
  38. strcpy(server_address, "127.0.0.1");
  39. auto closer = sg::make_scope_guard([&]() {
  40. free(server_address);
  41. });
  42. namespace bp = boost::process;
  43. bp::child *worker = nullptr;
  44. // main loop
  45. while (!glfwWindowShouldClose(main_window)) {
  46. glfwPollEvents();
  47. ImGui_ImplOpenGL3_NewFrame();
  48. ImGui_ImplGlfw_NewFrame();
  49. ImGui::NewFrame();
  50. // ImGui::ShowDemoWindow();
  51. if (ImGui::Begin("TinyPlayer Control")) {
  52. // action
  53. ImGui::SeparatorText("Actions");
  54. if (worker == nullptr) {
  55. if (ImGui::Button("Start")) {
  56. worker = new bp::child{this_name, std::to_string(monitor_index),
  57. server_address, std::to_string(server_port)};
  58. }
  59. } else {
  60. if (ImGui::Button("Stop")) {
  61. worker->terminate();
  62. worker = nullptr;
  63. }
  64. }
  65. // configs
  66. ImGui::SeparatorText("Configs");
  67. ImGui::PushItemWidth(200);
  68. if (worker != nullptr) {
  69. ImGui::BeginDisabled();
  70. }
  71. // monitor
  72. int monitor_count;
  73. auto monitors = glfwGetMonitors(&monitor_count);
  74. if (monitor_index >= monitor_count) {
  75. monitor_index = 0;
  76. }
  77. auto monitor_name_preview = glfwGetMonitorName(monitors[monitor_index]);
  78. if (ImGui::BeginCombo("Monitor", monitor_name_preview)) { // let user select monitors
  79. for (int k = 0; k < monitor_count; ++k) {
  80. auto is_selected = (monitor_index == k);
  81. auto monitor_name = fmt::format("{} - {}", k, glfwGetMonitorName(monitors[k]));
  82. if (ImGui::Selectable(monitor_name.c_str(), is_selected)) {
  83. monitor_index = k;
  84. }
  85. if (is_selected) {
  86. ImGui::SetItemDefaultFocus();
  87. }
  88. }
  89. ImGui::EndCombo();
  90. }
  91. // server address
  92. ImGui::InputText("Server IP", server_address, server_address_length);
  93. // server port
  94. static uint16_t val_one = 1;
  95. ImGui::InputScalar("Server Port", ImGuiDataType_U16, &server_port, &val_one, nullptr, "%u");
  96. if (worker != nullptr) {
  97. ImGui::EndDisabled();
  98. }
  99. ImGui::PopItemWidth();
  100. }
  101. ImGui::End();
  102. ImGui::Render();
  103. int frame_width, frame_height;
  104. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  105. glfwGetFramebufferSize(main_window, &frame_width, &frame_height);
  106. glViewport(0, 0, frame_width, frame_height);
  107. glClear(GL_COLOR_BUFFER_BIT);
  108. ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
  109. glfwSwapBuffers(main_window);
  110. }
  111. if (worker != nullptr) {
  112. worker->terminate();
  113. }
  114. }
  115. void render_main() {
  116. // setup cuda
  117. cuInit(0);
  118. CUcontext cuda_ctx;
  119. get_cuda_primary_context(&cuda_ctx);
  120. cuCtxPushCurrent(cuda_ctx);
  121. std::thread receiver_thread{[]() {
  122. // setup cuda
  123. CUcontext cuda_ctx;
  124. get_cuda_primary_context(&cuda_ctx);
  125. cuCtxPushCurrent(cuda_ctx);
  126. decoder.start();
  127. // frame_receiver receiver;
  128. // receiver.start(server_address, server_port, &decoder);
  129. auto conf = receiver_config{
  130. server_address, server_port, &decoder
  131. };
  132. auto receiver = std::unique_ptr<frame_receiver2>(frame_receiver2::create(conf));
  133. receiver->run();
  134. }};
  135. nv12_renderer renderer;
  136. while (!glfwWindowShouldClose(main_window)) {
  137. glfwPollEvents();
  138. // retrieve new image
  139. decoder.retrieve_frame(&renderer);
  140. // adjust window
  141. int fbo_width, fbo_height;
  142. glfwGetFramebufferSize(main_window, &fbo_width, &fbo_height);
  143. glViewport(0, 0, fbo_width, fbo_height);
  144. auto fbo_wh_ratio = 1.0f * fbo_width / fbo_height;
  145. // draw image
  146. renderer.render(fbo_wh_ratio);
  147. glfwSwapBuffers(main_window);
  148. glFinish();
  149. }
  150. }
  151. int main(int argc, char *argv[]) {
  152. #ifndef NDEBUG
  153. spdlog::set_level(spdlog::level::trace);
  154. #endif
  155. // config options
  156. bool is_controller = (argc == 1);
  157. if (!is_controller) {
  158. assert(argc == 4);
  159. monitor_index = std::atoi(argv[1]);
  160. server_address = argv[2];
  161. server_port = std::atoi(argv[3]);
  162. }
  163. // setup glfw
  164. glfwSetErrorCallback([](int error, const char *desc) {
  165. SPDLOG_ERROR("GLFW error: code = {}, description = {}", error, desc);
  166. assert(false);
  167. });
  168. auto ret = glfwInit();
  169. assert(ret == GLFW_TRUE);
  170. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
  171. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
  172. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  173. glfwWindowHint(GLFW_REFRESH_RATE, 60);
  174. // setup window
  175. if (is_controller) {
  176. main_window = glfwCreateWindow(main_window_width, main_window_height, "TinyPlayer Control", nullptr, nullptr);
  177. } else { // is render
  178. int monitor_count;
  179. auto monitors = glfwGetMonitors(&monitor_count);
  180. assert(monitor_count > monitor_index);
  181. auto monitor = monitors[monitor_index];
  182. auto video_mode = glfwGetVideoMode(monitor);
  183. // main_window = glfwCreateWindow(video_mode->width, video_mode->height, "TinyPlayer", monitor, nullptr);
  184. main_window = glfwCreateWindow(800, 600, "TinyPlayer", nullptr, nullptr);
  185. }
  186. glfwMakeContextCurrent(main_window);
  187. glfwSwapInterval(1);
  188. // load opengl functions
  189. auto version = gladLoadGL(glfwGetProcAddress);
  190. assert(version > 0);
  191. SPDLOG_INFO("Loaded OpenGL {}.{}", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
  192. #ifndef NDEBUG
  193. // log opengl error
  194. glEnable(GL_DEBUG_OUTPUT);
  195. glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity,
  196. GLsizei length, const GLchar *message, const void *user_data) {
  197. if (type == GL_DEBUG_TYPE_ERROR) {
  198. SPDLOG_ERROR("OpenGL error: type = {}, severity = {}, message = {}", type, severity, message);
  199. assert(false);
  200. }
  201. }, nullptr);
  202. #endif
  203. if (is_controller) {
  204. controller_main(argv[0]);
  205. } else {
  206. render_main();
  207. }
  208. return 0;
  209. }