#include "config.h" #include "cuda_helper.hpp" #include "frame_receiver.h" #include "frame_receiver2.h" #include "nv12_renderer.h" #include "third_party/scope_guard.hpp" #include "video_decoder.h" #include #include #include #include #include #include #include #include #ifdef _MSC_VER #include #define fmt std #endif // for renderer int monitor_index = 0; char *server_address; uint16_t server_port = 5277; GLFWwindow *main_window = nullptr; // for receiver video_decoder decoder; void controller_main(const char *this_name) { // setup imgui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); auto io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; ImGui::StyleColorsDark(); ImGui_ImplGlfw_InitForOpenGL(main_window, true); ImGui_ImplOpenGL3_Init(); static constexpr auto server_address_length = 256; server_address = (char *) malloc(server_address_length); strcpy(server_address, "127.0.0.1"); auto closer = sg::make_scope_guard([&]() { free(server_address); }); namespace bp = boost::process; bp::child *worker = nullptr; // main loop while (!glfwWindowShouldClose(main_window)) { glfwPollEvents(); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); // ImGui::ShowDemoWindow(); if (ImGui::Begin("TinyPlayer Control")) { // action ImGui::SeparatorText("Actions"); if (worker == nullptr) { if (ImGui::Button("Start")) { worker = new bp::child{this_name, std::to_string(monitor_index), server_address, std::to_string(server_port)}; } } else { if (ImGui::Button("Stop")) { worker->terminate(); worker = nullptr; } } // configs ImGui::SeparatorText("Configs"); ImGui::PushItemWidth(200); if (worker != nullptr) { ImGui::BeginDisabled(); } // monitor int monitor_count; auto monitors = glfwGetMonitors(&monitor_count); if (monitor_index >= monitor_count) { monitor_index = 0; } auto monitor_name_preview = glfwGetMonitorName(monitors[monitor_index]); if (ImGui::BeginCombo("Monitor", monitor_name_preview)) { // let user select monitors for (int k = 0; k < monitor_count; ++k) { auto is_selected = (monitor_index == k); auto monitor_name = fmt::format("{} - {}", k, glfwGetMonitorName(monitors[k])); if (ImGui::Selectable(monitor_name.c_str(), is_selected)) { monitor_index = k; } if (is_selected) { ImGui::SetItemDefaultFocus(); } } ImGui::EndCombo(); } // server address ImGui::InputText("Server IP", server_address, server_address_length); // server port static uint16_t val_one = 1; ImGui::InputScalar("Server Port", ImGuiDataType_U16, &server_port, &val_one, nullptr, "%u"); if (worker != nullptr) { ImGui::EndDisabled(); } ImGui::PopItemWidth(); } ImGui::End(); ImGui::Render(); int frame_width, frame_height; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glfwGetFramebufferSize(main_window, &frame_width, &frame_height); glViewport(0, 0, frame_width, frame_height); glClear(GL_COLOR_BUFFER_BIT); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(main_window); } if (worker != nullptr) { worker->terminate(); } } void render_main() { // setup cuda cuInit(0); CUcontext cuda_ctx; get_cuda_primary_context(&cuda_ctx); cuCtxPushCurrent(cuda_ctx); std::thread receiver_thread{[]() { // setup cuda CUcontext cuda_ctx; get_cuda_primary_context(&cuda_ctx); cuCtxPushCurrent(cuda_ctx); decoder.start(); // frame_receiver receiver; // receiver.start(server_address, server_port, &decoder); auto conf = receiver_config{ server_address, server_port, &decoder }; auto receiver = std::unique_ptr(frame_receiver2::create(conf)); receiver->run(); }}; nv12_renderer renderer; while (!glfwWindowShouldClose(main_window)) { glfwPollEvents(); // retrieve new image decoder.retrieve_frame(&renderer); // adjust window int fbo_width, fbo_height; glfwGetFramebufferSize(main_window, &fbo_width, &fbo_height); glViewport(0, 0, fbo_width, fbo_height); auto fbo_wh_ratio = 1.0f * fbo_width / fbo_height; // draw image renderer.render(fbo_wh_ratio); glfwSwapBuffers(main_window); glFinish(); } } int main(int argc, char *argv[]) { #ifndef NDEBUG spdlog::set_level(spdlog::level::trace); #endif // config options bool is_controller = (argc == 1); if (!is_controller) { assert(argc == 4); monitor_index = std::atoi(argv[1]); server_address = argv[2]; server_port = std::atoi(argv[3]); } // setup glfw glfwSetErrorCallback([](int error, const char *desc) { SPDLOG_ERROR("GLFW error: code = {}, description = {}", error, desc); assert(false); }); auto ret = glfwInit(); assert(ret == GLFW_TRUE); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_REFRESH_RATE, 60); // setup window if (is_controller) { main_window = glfwCreateWindow(main_window_width, main_window_height, "TinyPlayer Control", nullptr, nullptr); } else { // is render int monitor_count; auto monitors = glfwGetMonitors(&monitor_count); assert(monitor_count > monitor_index); auto monitor = monitors[monitor_index]; auto video_mode = glfwGetVideoMode(monitor); // main_window = glfwCreateWindow(video_mode->width, video_mode->height, "TinyPlayer", monitor, nullptr); main_window = glfwCreateWindow(800, 600, "TinyPlayer", nullptr, nullptr); } glfwMakeContextCurrent(main_window); glfwSwapInterval(1); // load opengl functions auto version = gladLoadGL(glfwGetProcAddress); assert(version > 0); SPDLOG_INFO("Loaded OpenGL {}.{}", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version)); #ifndef NDEBUG // log opengl error glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user_data) { if (type == GL_DEBUG_TYPE_ERROR) { SPDLOG_ERROR("OpenGL error: type = {}, severity = {}, message = {}", type, severity, message); assert(false); } }, nullptr); #endif if (is_controller) { controller_main(argv[0]); } else { render_main(); } return 0; }