From c651ba21a21ef3977365a34ec339faa180421109 Mon Sep 17 00:00:00 2001 From: milek7 Date: Sat, 7 Sep 2019 02:06:09 +0200 Subject: [PATCH] extcam camera preview --- CMakeLists.txt | 14 ++- Globals.cpp | 10 ++ Globals.h | 5 + driveruilayer.h | 6 +- extras/piped_proc.cpp | 87 +++++++++++++++ extras/piped_proc.h | 28 +++++ widgets/cameraview_extcam.cpp | 105 ++++++++++++++++++ widgets/cameraview_extcam.h | 31 ++++++ .../{cameraview.cpp => cameraview_vsdev.cpp} | 2 +- widgets/{cameraview.h => cameraview_vsdev.h} | 0 10 files changed, 283 insertions(+), 5 deletions(-) create mode 100644 extras/piped_proc.cpp create mode 100644 extras/piped_proc.h create mode 100644 widgets/cameraview_extcam.cpp create mode 100644 widgets/cameraview_extcam.h rename widgets/{cameraview.cpp => cameraview_vsdev.cpp} (98%) rename widgets/{cameraview.h => cameraview_vsdev.h} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78b5fce5..7168896d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,8 @@ file(GLOB HEADERS "*.h" "network/*.h" "network/backend/*.h" "widgets/*.h" -"launcher/*.h") +"launcher/*.h" +"extras/*.h") if (APPLE) set (CMAKE_EXE_LINKER_FLAGS "-pagezero_size 10000 -image_base 100000000") @@ -37,6 +38,7 @@ endif() option(USE_IMGUI_GL3 "Use OpenGL3+ imgui implementation" ON) option(WITH_UART "Compile with libserialport" ON) +option(USE_VSDEV_CAMERA "Use VS_Dev camera preview implementation" OFF) set(SOURCES "Texture.cpp" @@ -140,7 +142,6 @@ set(SOURCES "widgets/vehicleparams.cpp" "widgets/trainingcard.cpp" "widgets/perfgraphs.cpp" -"widgets/cameraview.cpp" "ref/glad/src/glad.c" @@ -163,7 +164,6 @@ set(SOURCES "imgui/imgui_impl_glfw.cpp" "stb/stb_image.c" -"extras/VS_Dev.cpp" "launcher/launchermode.cpp" "launcher/scenery_list.cpp" @@ -186,6 +186,14 @@ if (WITH_UART) set(SOURCES ${SOURCES} "uart.cpp") endif() +if (USE_VSDEV_CAMERA) + add_definitions(-DUSE_VSDEV_CAMERA) + set(SOURCES ${SOURCES} "extras/VS_Dev.cpp" "widgets/cameraview_vsdev.cpp") +else() + add_definitions(-DUSE_EXTCAM_CAMERA) + set(SOURCES ${SOURCES} "extras/piped_proc.cpp" "widgets/cameraview_extcam.cpp") +endif() + set (PREFIX "") if (WIN32) diff --git a/Globals.cpp b/Globals.cpp index f7815e83..4c58ea6d 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -702,6 +702,16 @@ global_settings::ConfigParse(cParser &Parser) { Parser.getTokens( 1 ); Parser >> uart_conf.debug; } +#endif +#ifdef USE_EXTCAM_CAMERA + else if( token == "extcam.cmd" ) { + Parser.getTokens( 1 ); + Parser >> extcam_cmd; + } + else if( token == "extcam.res" ) { + Parser.getTokens( 2 ); + Parser >> extcam_res.x >> extcam_res.y; + } #endif else if (token == "loadinglog") { Parser.getTokens( 1 ); diff --git a/Globals.h b/Globals.h index 5fd3f3e4..74c293ad 100644 --- a/Globals.h +++ b/Globals.h @@ -187,6 +187,11 @@ struct global_settings { bool captureonstart = true; bool render_cab = true; +#ifdef USE_EXTCAM_CAMERA + std::string extcam_cmd; + glm::ivec2 extcam_res{800, 600}; +#endif + std::chrono::duration minframetime {0.0f}; std::string fullscreen_monitor; diff --git a/driveruilayer.h b/driveruilayer.h index b4ddb283..6be4f620 100644 --- a/driveruilayer.h +++ b/driveruilayer.h @@ -18,8 +18,12 @@ http://mozilla.org/MPL/2.0/. #include "widgets/map.h" #include "widgets/time.h" #include "widgets/trainingcard.h" -#include "widgets/cameraview.h" #include "widgets/perfgraphs.h" +#ifdef USE_EXTCAM_CAMERA +#include "widgets/cameraview_extcam.h" +#elif USE_VSDEV_CAMERA +#include "widgets/cameraview_vsdev.h" +#endif class driver_ui : public ui_layer { diff --git a/extras/piped_proc.cpp b/extras/piped_proc.cpp new file mode 100644 index 00000000..e75a97dc --- /dev/null +++ b/extras/piped_proc.cpp @@ -0,0 +1,87 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "stdafx.h" +#include "piped_proc.h" +#include "Logs.h" + +#ifdef __unix__ +piped_proc::piped_proc(std::string cmd) +{ + file = popen(cmd.c_str(), "r"); +} + +piped_proc::~piped_proc() +{ + if (file) + pclose(file); +} + +size_t piped_proc::read(unsigned char *buf, size_t len) +{ + if (!file) + return 0; + + return fread(buf, 1, len, file); +} +#elif _WIN32 +piped_proc::piped_proc(std::string cmd) +{ + PROCESS_INFORMATION process; + STARTUPINFO siStartInfo; + SECURITY_ATTRIBUTES saAttr; + + memset(&process, 0, sizeof(PROCESS_INFORMATION)); + memset(&siStartInfo, 0, sizeof(STARTUPINFO)); + memset(&saAttr, 0, sizeof(SECURITY_ATTRIBUTES)); + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&pipe_rd, &pipe_wr, &saAttr, 0)) { + ErrorLog("piped_proc: CreatePipe failed!"); + return; + } + + if (!SetHandleInformation(pipe_rd, HANDLE_FLAG_INHERIT, 0)) { + ErrorLog("piped_proc: SetHandleInformation failed!"); + return; + } + + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + siStartInfo.hStdOutput = pipe_wr; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + if (!CreateProcessA(NULL, (char*)cmd.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &process)) { + ErrorLog("piped_proc: CreateProcess failed!"); + return; + } + + if (process.hProcess) + CloseHandle(process.hProcess); + if (process.hThread) + CloseHandle(process.hThread); +} + +piped_proc::~piped_proc() +{ + if (pipe_wr) + CloseHandle(pipe_wr); + if (pipe_rd) + CloseHandle(pipe_rd); +} + +size_t piped_proc::read(unsigned char *buf, size_t len) +{ + if (!pipe_rd) + return 0; + + DWORD read = 0; + BOOL ret = ReadFile(pipe_rd, buf, len, &read, NULL); + + return read; +} +#endif diff --git a/extras/piped_proc.h b/extras/piped_proc.h new file mode 100644 index 00000000..5c5bf2b0 --- /dev/null +++ b/extras/piped_proc.h @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#ifdef __unix__ +#include +#elif _WIN32 +#include "winheaders.h" +#endif +#include + +class piped_proc +{ +private: +#ifdef __unix__ +FILE *file = nullptr; +#elif _WIN32 +HANDLE pipe_rd = nullptr; +HANDLE pipe_wr = nullptr; +#endif + +public: + piped_proc(std::string cmd); + size_t read(unsigned char *buf, size_t len); + ~piped_proc(); +}; diff --git a/widgets/cameraview_extcam.cpp b/widgets/cameraview_extcam.cpp new file mode 100644 index 00000000..96961a81 --- /dev/null +++ b/widgets/cameraview_extcam.cpp @@ -0,0 +1,105 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "stdafx.h" +#include "widgets/cameraview_extcam.h" +#include "stb/stb_image.h" +#include "Globals.h" +#include "Logs.h" +#include "extras/piped_proc.h" + +ui::cameraview_panel::cameraview_panel() + : ui_panel(STR_C("Camera preview"), false) +{ + size_min = { -2, -2 }; +} + +void cameraview_window_callback(ImGuiSizeCallbackData *data) { + data->DesiredSize.y = data->DesiredSize.x * (float)Global.extcam_res.y / (float)Global.extcam_res.x; +} + +ui::cameraview_panel::~cameraview_panel() { + exit_thread = true; + if (workthread.joinable()) + workthread.detach(); +} + +void ui::cameraview_panel::render() +{ + if (!is_open) + exit_thread = true; + + if (is_open) + ImGui::SetNextWindowSizeConstraints(ImVec2(200, 200), ImVec2(2500, 2500), cameraview_window_callback); + + ui_panel::render(); +} + +void ui::cameraview_panel::render_contents() +{ + if (exit_thread) { + if (workthread.joinable()) + workthread.join(); + exit_thread = false; + if (!Global.extcam_cmd.empty()) + workthread = std::thread(&cameraview_panel::workthread_func, this); + } + + if (!texture) { + texture.emplace(); + texture->make_stub(); + } + + texture->bind(0); + + { + std::lock_guard lock(mutex); + if (image_ptr) { + + glActiveTexture(GL_TEXTURE0); + + glTexImage2D( + GL_TEXTURE_2D, 0, + GL_SRGB8_ALPHA8, + Global.extcam_res.x, Global.extcam_res.y, 0, + GL_RGB, GL_UNSIGNED_BYTE, image_ptr); + image_ptr = nullptr; + + if (Global.python_mipmaps) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glGenerateMipmap(GL_TEXTURE_2D); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + } + } + + ImVec2 surface_size = ImGui::GetContentRegionAvail(); + ImGui::Image(reinterpret_cast(texture->id), surface_size); +} + +void ui::cameraview_panel::workthread_func() +{ + piped_proc proc(Global.extcam_cmd); + + size_t frame_size = Global.extcam_res.x * Global.extcam_res.y * 3; + uint8_t *read_buffer = new uint8_t[frame_size]; + uint8_t *active_buffer = new uint8_t[frame_size]; + + while (!exit_thread) { + if (proc.read(read_buffer, frame_size) != frame_size) + break; + + std::lock_guard lock(mutex); + image_ptr = read_buffer; + read_buffer = active_buffer; + active_buffer = image_ptr; + } + + std::lock_guard lock(mutex); + image_ptr = nullptr; + delete[] read_buffer; + delete[] active_buffer; +} diff --git a/widgets/cameraview_extcam.h b/widgets/cameraview_extcam.h new file mode 100644 index 00000000..fcf1c69b --- /dev/null +++ b/widgets/cameraview_extcam.h @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "stdafx.h" +#include "uilayer.h" + +namespace ui +{ +class cameraview_panel : public ui_panel +{ + std::atomic_bool exit_thread = true; + std::thread workthread; + + uint8_t* image_ptr = nullptr; + std::mutex mutex; + + std::optional texture; + + void workthread_func(); + + public: + cameraview_panel(); + ~cameraview_panel(); + + void render() override; + void render_contents() override; +}; +} // namespace ui diff --git a/widgets/cameraview.cpp b/widgets/cameraview_vsdev.cpp similarity index 98% rename from widgets/cameraview.cpp rename to widgets/cameraview_vsdev.cpp index ae6e660b..f049a599 100644 --- a/widgets/cameraview.cpp +++ b/widgets/cameraview_vsdev.cpp @@ -1,5 +1,5 @@ #include "stdafx.h" -#include "widgets/cameraview.h" +#include "widgets/cameraview_vsdev.h" #include "stb/stb_image.h" #include "Globals.h" #include "Logs.h" diff --git a/widgets/cameraview.h b/widgets/cameraview_vsdev.h similarity index 100% rename from widgets/cameraview.h rename to widgets/cameraview_vsdev.h