diff options
Diffstat (limited to 'video-ps3eye')
-rw-r--r-- | video-ps3eye/CMakeLists.txt | 43 | ||||
-rw-r--r-- | video-ps3eye/dialog.ui | 133 | ||||
-rw-r--r-- | video-ps3eye/lang/nl_NL.ts | 19 | ||||
-rw-r--r-- | video-ps3eye/lang/ru_RU.ts | 19 | ||||
-rw-r--r-- | video-ps3eye/lang/stub.ts | 19 | ||||
-rw-r--r-- | video-ps3eye/lang/zh_CN.ts | 19 | ||||
-rw-r--r-- | video-ps3eye/module.cpp | 220 | ||||
-rw-r--r-- | video-ps3eye/module.hpp | 91 | ||||
m--------- | video-ps3eye/ps3eye-driver | 0 | ||||
-rw-r--r-- | video-ps3eye/shm-layout.hpp | 27 | ||||
-rw-r--r-- | video-ps3eye/shm.cxx | 2 | ||||
-rw-r--r-- | video-ps3eye/shm.hpp | 4 | ||||
-rw-r--r-- | video-ps3eye/wrapper.cxx | 110 |
13 files changed, 634 insertions, 72 deletions
diff --git a/video-ps3eye/CMakeLists.txt b/video-ps3eye/CMakeLists.txt index 2fac5f9c..2f0bf50b 100644 --- a/video-ps3eye/CMakeLists.txt +++ b/video-ps3eye/CMakeLists.txt @@ -10,6 +10,7 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ps3eye-driver/CMakeLists.txt") if(libusb_FOUND) include_directories(SYSTEM ${libusb_INCLUDE_DIRS}) link_libraries(${libusb_LIBRARIES}) + link_directories(${libusb_LIBRARY_DIRS}) endif() else() set(SDK_LIBUSB CACHE PATH "") @@ -21,26 +22,14 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ps3eye-driver/CMakeLists.txt") endif() endif() -if(TARGET ps3eye-driver) - otr_module(video-ps3eye) - link_libraries(ps3eye-driver) - add_executable(ps3eye-subprocess "wrapper.cxx") - if(WIN32) - set(path "${SDK_LIBUSB}/libusb-1.0.dll") - if(EXISTS "${path}") - otr_install_lib("${path}" "${opentrack-hier-pfx}") - endif() - endif() -endif() - -if(TARGET ps3eye-sdl) - install(TARGETS "ps3eye-sdl" DESTINATION "${opentrack-hier-pfx}") +if(TARGET ps3eye-sdl AND FALSE) + install(TARGETS "ps3eye-sdl" DESTINATION "${opentrack-libexec}") if(WIN32) foreach(k ${SDL2_LIBRARIES}) get_filename_component(path "${k}" PATH) set(lib "${path}/SDL2.dll") if(EXISTS "${lib}") - otr_install_lib("${lib}" "${opentrack-hier-pfx}") + otr_install_lib("${lib}" "${opentrack-libexec}") break() endif() endforeach() @@ -48,9 +37,29 @@ if(TARGET ps3eye-sdl) endif() if(TARGET ps3eye-mode-test) - install(TARGETS "ps3eye-mode-test" DESTINATION "${opentrack-hier-pfx}") + install(TARGETS "ps3eye-mode-test" DESTINATION "${opentrack-libexec}") +endif() + +if(TARGET ps3eye-driver) + add_executable(ps3eye-subprocess "wrapper.cxx" "shm.cxx") + target_link_libraries(ps3eye-subprocess ps3eye-driver) + if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + target_link_libraries(ps3eye-subprocess rt) + endif() + install(TARGETS "ps3eye-subprocess" DESTINATION "${opentrack-libexec}") +endif() + +if(TARGET ps3eye-subprocess) + otr_module(video-ps3eye) + target_link_libraries(${self} ps3eye-driver opentrack-video) + if(WIN32) + set(path "${SDK_LIBUSB}/libusb-1.0.dll") + if(EXISTS "${path}") + otr_install_lib("${path}" "${opentrack-libexec}") + endif() + endif() endif() if(TARGET ps3eye-frame-test) - install(TARGETS "ps3eye-frame-test" DESTINATION "${opentrack-hier-pfx}") + install(TARGETS "ps3eye-frame-test" DESTINATION "${opentrack-libexec}") endif() diff --git a/video-ps3eye/dialog.ui b/video-ps3eye/dialog.ui new file mode 100644 index 00000000..1e94ce74 --- /dev/null +++ b/video-ps3eye/dialog.ui @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QWidget" name="Dialog"> + <property name="windowModality"> + <enum>Qt::ApplicationModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>439</width> + <height>211</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>439</width> + <height>0</height> + </size> + </property> + <property name="windowTitle"> + <string>PS3 Eye</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Camera settings</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="2"> + <widget class="QSpinBox" name="exposure_label"> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="maximum"> + <number>255</number> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QSpinBox" name="gain_label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="maximum"> + <number>63</number> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSlider" name="exposure_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximum"> + <number>255</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Exposure</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSlider" name="gain_slider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximum"> + <number>63</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Gain</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/video-ps3eye/lang/nl_NL.ts b/video-ps3eye/lang/nl_NL.ts index 6401616d..c98370ec 100644 --- a/video-ps3eye/lang/nl_NL.ts +++ b/video-ps3eye/lang/nl_NL.ts @@ -1,4 +1,23 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> +<context> + <name>Dialog</name> + <message> + <source>PS3 Eye</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Camera settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Exposure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Gain</source> + <translation type="unfinished"></translation> + </message> +</context> </TS> diff --git a/video-ps3eye/lang/ru_RU.ts b/video-ps3eye/lang/ru_RU.ts index 6401616d..c98370ec 100644 --- a/video-ps3eye/lang/ru_RU.ts +++ b/video-ps3eye/lang/ru_RU.ts @@ -1,4 +1,23 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> +<context> + <name>Dialog</name> + <message> + <source>PS3 Eye</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Camera settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Exposure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Gain</source> + <translation type="unfinished"></translation> + </message> +</context> </TS> diff --git a/video-ps3eye/lang/stub.ts b/video-ps3eye/lang/stub.ts index 6401616d..c98370ec 100644 --- a/video-ps3eye/lang/stub.ts +++ b/video-ps3eye/lang/stub.ts @@ -1,4 +1,23 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> +<context> + <name>Dialog</name> + <message> + <source>PS3 Eye</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Camera settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Exposure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Gain</source> + <translation type="unfinished"></translation> + </message> +</context> </TS> diff --git a/video-ps3eye/lang/zh_CN.ts b/video-ps3eye/lang/zh_CN.ts index 6401616d..c98370ec 100644 --- a/video-ps3eye/lang/zh_CN.ts +++ b/video-ps3eye/lang/zh_CN.ts @@ -1,4 +1,23 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.1"> +<context> + <name>Dialog</name> + <message> + <source>PS3 Eye</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Camera settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Exposure</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Gain</source> + <translation type="unfinished"></translation> + </message> +</context> </TS> diff --git a/video-ps3eye/module.cpp b/video-ps3eye/module.cpp index ac6d8807..a7078180 100644 --- a/video-ps3eye/module.cpp +++ b/video-ps3eye/module.cpp @@ -1,7 +1,22 @@ #include "module.hpp" -#if 0 +#include "compat/library-path.hpp" +#include "compat/sleep.hpp" +#include "compat/run-in-thread.hpp" + +#include <cstddef> +#include <thread> + +#include <QCoreApplication> +#include <QMessageBox> + #include <libusb.h> +using namespace options; + +#ifdef __GNUG__ +# pragma clang diagnostic ignored "-Wcast-qual" +#endif + int device_count() { libusb_context * ctx = nullptr; @@ -42,16 +57,24 @@ end: return cnt; } +#ifdef __linux__ +# include <unistd.h> +#endif + bool check_device_exists() { +#ifdef __linux__ + // don't show when system driver exists + if (!access("/sys/module/gspca_ov534", R_OK|X_OK)) + return false; +#endif + static bool ret = device_count() > 0; return ret; } static const QString camera_name = QStringLiteral("PS3 Eye open driver"); -namespace video::impl { - std::vector<QString> ps3eye_camera_::camera_names() const { if (check_device_exists()) @@ -66,16 +89,195 @@ std::unique_ptr<camera> ps3eye_camera_::make_camera(const QString& name) else return {}; } -bool ps3eye_camera_::show_dialog(const QString& camera_name) + +static bool show_dialog_() { - // TODO - return false; + (new dialog)->show(); + return true; } -bool ps3eye_camera_::can_show_dialog(const QString& camera_name) + +bool ps3eye_camera_::show_dialog(const QString&) { - return false; + return show_dialog_(); } -} // ns video::impl +bool ps3eye_camera_::can_show_dialog(const QString& name) +{ + return name == camera_name && check_device_exists(); +} + +ps3eye_camera::ps3eye_camera() +{ + if (!shm.success()) + return; + + static const QString library_path(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH); + wrapper.setWorkingDirectory(library_path); +#ifdef _WIN32 + wrapper.setProgram("\"ps3eye-subprocess.exe\""); +#else + wrapper.setProgram("ps3eye-subprocess"); #endif +} + +ps3eye_camera::~ps3eye_camera() +{ + stop(); +} + +void ps3eye_camera::stop() +{ + open = false; + + if (wrapper.state() != QProcess::NotRunning) + { + if (wrapper.state() != QProcess::NotRunning) + wrapper.kill(); + wrapper.waitForFinished(1000); + } +} + +bool ps3eye_camera::start(info& args) +{ + if (!shm.success()) + return false; + + volatile auto& ptr = *(ps3eye::shm*)shm.ptr(); + QString error; + + using mode = ps3eye::shm_in::mode; + + open = false; + fr = {}; + fr.channels = 3; + fr.channel_size = 1; + + if (!args.width || args.width > 320) + { + ptr.in.resolution = mode::vga; + fr.width = 640; fr.height = 480; + } + else + { + ptr.in.resolution = mode::qvga; + fr.width = 320; fr.height = 240; + } + + ptr.in.auto_gain = false; + ptr.in.framerate = (uint8_t)std::clamp(args.fps, 30, 187); + ptr.in.gain = (uint8_t)s.gain; + ptr.in.exposure = (uint8_t)s.exposure; + + sleep_ms = std::clamp(int(std::floor(1000./ptr.in.framerate*2)), 1, 10); + + wrapper.start(); + + constexpr int sleep_ms = 10, max_sleeps = 5000/sleep_ms; + + for (int i = 0; i < max_sleeps; i++) + { + if (ptr.out.timecode > 0) + goto ok; + portable::sleep(sleep_ms); + } + + if (ptr.out.error_string[0] == '\0') + error = "Unknown error"; + else + error = QString::fromLatin1((const char*)ptr.out.error_string, + strnlen((const char*)ptr.out.error_string, sizeof(ptr.out.error_string))); + + run_in_thread_async(qApp, [=]() { + QMessageBox::critical(nullptr, "Can't open camera", "PS3 Eye driver error: " + error, QMessageBox::Close); + }); + + return false; + +ok: + open = true; + return true; +} + +std::tuple<const frame&, bool> ps3eye_camera::get_frame() +{ + auto volatile* ptr = (ps3eye::shm*)shm.ptr(); + + if (shm.success() && open) + { + int elapsed = std::min((int)std::ceil(t.elapsed_ms()), 100); + portable::sleep(sleep_ms - elapsed); + + if (unsigned tc = ptr->out.timecode; tc != timecode) + { + timecode = tc; + goto ok; + } + } + + for (int i = 0; i < 2000; i++) + { + if (unsigned tc = ptr->out.timecode; tc != timecode) + { + timecode = tc; + goto ok; + } + portable::sleep(1); + } + + stop(); + return { fr, false }; + + static_assert(offsetof(decltype(ptr->out), data_640x480) == offsetof(decltype(ptr->out), data_320x240)); + +ok: + t.start(); + memcpy(data, (unsigned char*)ptr->out.data_640x480,sizeof(ptr->out.data_640x480)); + fr.data = data; + return { fr, true }; +} + +bool ps3eye_camera::show_dialog() +{ + return show_dialog_(); +} + +OTR_REGISTER_CAMERA(ps3eye_camera_) + +dialog::dialog(QWidget* parent) : QWidget(parent) +{ + ui.setupUi(this); + tie_setting(s.exposure, ui.exposure_slider); + tie_setting(s.gain, ui.gain_slider); + ui.exposure_label->setValue((int)*s.exposure); + ui.gain_label->setValue((int)*s.gain); + connect(&s.exposure, value_::value_changed<slider_value>(), this, [this](const slider_value&) { s.set_exposure(); }); + connect(&s.gain, value_::value_changed<slider_value>(), this, [this](const slider_value&) { s.set_gain(); }); + connect(ui.exposure_slider, &QSlider::valueChanged, ui.exposure_label, &QSpinBox::setValue); + connect(ui.gain_slider, &QSlider::valueChanged, ui.gain_label, &QSpinBox::setValue); + connect(ui.buttonBox, &QDialogButtonBox::accepted, this, &dialog::do_ok); + connect(ui.buttonBox, &QDialogButtonBox::rejected, this, &dialog::do_cancel); +} + +// XXX copypasta -sh 20200329 +void settings::set_gain() +{ + if (!shm.success()) + return; + + auto& ptr = *(ps3eye::shm volatile*)shm.ptr(); + ptr.in.gain = (unsigned char)*gain; + ++ptr.in.settings_updated; + std::atomic_thread_fence(std::memory_order_seq_cst); +} + +void settings::set_exposure() +{ + if (!shm.success()) + return; + + auto& ptr = *(ps3eye::shm volatile*)shm.ptr(); + ptr.in.exposure = (unsigned char)*exposure; + ++ptr.in.settings_updated; + std::atomic_thread_fence(std::memory_order_seq_cst); +} diff --git a/video-ps3eye/module.hpp b/video-ps3eye/module.hpp index 357af14c..56ffe5df 100644 --- a/video-ps3eye/module.hpp +++ b/video-ps3eye/module.hpp @@ -1,54 +1,79 @@ #pragma once #include "video/camera.hpp" +#include "shm-layout.hpp" +#include "compat/shm.h" +#include "options/options.hpp" +#include "compat/macros1.h" +#include "compat/timer.hpp" +#include "ui_dialog.h" -#if 0 +#include <QDialog> +#include <QProcess> -namespace video { +using namespace options; -struct OTR_VIDEO_EXPORT camera_ +using video::impl::camera; +using video::impl::camera_; +using video::frame; + +struct settings final { - camera_(); - virtual ~camera_(); + bundle b = make_bundle("video-ps3eye"); + shm_wrapper shm { "ps3eye-driver-shm", nullptr, sizeof(ps3eye::shm) }; + + value<slider_value> exposure{b, "exposure", {255, 0, 255}}; + value<slider_value> gain{b, "gain", {30, 0, 63}}; - virtual std::vector<QString> camera_names() const = 0; - virtual std::unique_ptr<camera> make_camera(const QString& name) = 0; - virtual bool show_dialog(const QString& camera_name) = 0; - virtual bool can_show_dialog(const QString& camera_name) = 0; + void set_exposure(); + void set_gain(); }; -struct OTR_VIDEO_EXPORT camera +class dialog final : public QWidget { - struct info final - { - // TODO: expose FOV-based focal length for regular webcams - int width = 0, height = 0, fps = 0; - double fx = 0, fy = 0; // focal length - double P_x = 0, P_y = 0; // principal point - double dist_c[8] {}; // distortion coefficients - }; - - camera(); - virtual ~camera(); - - [[nodiscard]] virtual bool start(info& args) = 0; - virtual void stop() = 0; - virtual bool is_open() = 0; - - virtual std::tuple<const frame&, bool> get_frame() = 0; - [[nodiscard]] virtual bool show_dialog() = 0; + Q_OBJECT + Ui_Dialog ui; + settings s; + + shm_wrapper shm { "ps3eye-driver-shm", nullptr, sizeof(ps3eye::shm) }; + + void do_ok() { s.b->save(); close(); deleteLater(); } + void do_cancel() { s.b->reload(); close(); deleteLater(); } + +protected: + void closeEvent(QCloseEvent*) override { do_cancel(); } + +public: + explicit dialog(QWidget* parent = nullptr); }; -} // ns video +struct ps3eye_camera final : video::impl::camera +{ + QProcess wrapper; + shm_wrapper shm { "ps3eye-driver-shm", nullptr, sizeof(ps3eye::shm) }; + settings s; + frame fr; + Timer t; + unsigned char data[640 * 480 * 3] = {}; + int framerate = 30, sleep_ms = 1; + bool open = false; + unsigned timecode = 0; + + ps3eye_camera(); + ~ps3eye_camera() override; -#endif + bool start(info& args) override; + void stop() override; + bool is_open() override { return open; } + + std::tuple<const frame&, bool> get_frame() override; + [[nodiscard]] bool show_dialog() override; +}; -namespace video::impl { -struct ps3eye_camera_ : camera_ +struct ps3eye_camera_ final : video::impl::camera_ { std::vector<QString> camera_names() const override; std::unique_ptr<camera> make_camera(const QString& name) override; bool show_dialog(const QString& camera_name) override; bool can_show_dialog(const QString& camera_name) override; }; -} // ns video::impl diff --git a/video-ps3eye/ps3eye-driver b/video-ps3eye/ps3eye-driver -Subproject 7a2dcb0ff586bd0865d35d964b75c4d0a29b4e9 +Subproject ac056aa85dca83be3b1a14df7b20fd07104e052 diff --git a/video-ps3eye/shm-layout.hpp b/video-ps3eye/shm-layout.hpp index 7fa29115..577021b9 100644 --- a/video-ps3eye/shm-layout.hpp +++ b/video-ps3eye/shm-layout.hpp @@ -3,21 +3,25 @@ namespace ps3eye { -struct shm_out { +struct shm_in { enum class mode : uint8_t { qvga, vga, }; - enum class status : uint8_t { starting, running, fail, terminate, }; - uint8_t settings_updated; - uint16_t framerate; + uint32_t settings_updated; + uint8_t framerate; mode resolution; - status status_; - uint8_t sharpness, contrast, brightness, hue, saturation; - uint8_t gain, exposure, auto_gain, awb, test_pattern; + //uint8_t sharpness, contrast, brightness hue, saturation; + uint8_t gain, exposure, auto_gain, test_pattern; + uint8_t do_exit; }; -struct shm_in { - uint8_t settings_updated_ack; - uint8_t timecode; +struct shm_out +{ + enum class status : uint8_t { starting, running, fail, terminate, }; + + uint32_t timecode; + uint32_t settings_updated_ack; + status status_; + char error_string[256]; union { uint8_t data_320x240[320][240][3]; uint8_t data_640x480[640][480][3]; @@ -29,9 +33,6 @@ struct shm { static constexpr unsigned _padding_len = (_cacheline_len - (sizeof(shm_in) & (_cacheline_len - 1))) & (_cacheline_len - 1); - using resolution = shm_out::mode; - using status = shm_out::status; - shm_out out; const char* _padding[_padding_len]; shm_in in; diff --git a/video-ps3eye/shm.cxx b/video-ps3eye/shm.cxx new file mode 100644 index 00000000..57e35c3a --- /dev/null +++ b/video-ps3eye/shm.cxx @@ -0,0 +1,2 @@ +#include "shm.hpp" +#include "../compat/shm.cpp" diff --git a/video-ps3eye/shm.hpp b/video-ps3eye/shm.hpp new file mode 100644 index 00000000..2bb8cb89 --- /dev/null +++ b/video-ps3eye/shm.hpp @@ -0,0 +1,4 @@ +#pragma once +#define OTR_GENERIC_EXPORT +#define OTR_GENERIC_IMPORT +#include "../compat/shm.h" diff --git a/video-ps3eye/wrapper.cxx b/video-ps3eye/wrapper.cxx index add62992..eca8968d 100644 --- a/video-ps3eye/wrapper.cxx +++ b/video-ps3eye/wrapper.cxx @@ -1,7 +1,117 @@ #include "shm-layout.hpp" +#include "shm.hpp" + +#include "ps3eye-driver/ps3eye.hpp" + +#include <cstdlib> +#include <atomic> + +#ifdef __clang__ +# pragma clang diagnostic ignored "-Watomic-implicit-seq-cst" +#endif + +#ifdef __GNUG__ +# pragma GCC diagnostic ignored "-Wcast-qual" +# pragma GCC diagnostic ignored "-Wformat-security" +# pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif + +template<int N, typename... xs> +[[noreturn]] +static void error(volatile ps3eye::shm_out& out, const char (&error)[N], const xs&... args) +{ + snprintf((char*)out.error_string, sizeof(ps3eye::shm_out::error_string), error, args...); + std::quick_exit(2); +} + +static void update_settings(ps3eye::camera& camera, const volatile ps3eye::shm_in& in) +{ + //camera.set_framerate(in.framerate); + camera.set_auto_gain(in.auto_gain); + camera.set_gain(in.gain); + camera.set_exposure(in.exposure); + camera.set_test_pattern_status(in.test_pattern); +} + +static ps3eye::resolution get_mode(ps3eye::shm_in::mode res) +{ + switch (res) + { + default: + case ps3eye::shm_in::mode::qvga: + return ps3eye::res_QVGA; + case ps3eye::shm_in::mode::vga: + return ps3eye::res_VGA; + } +} int main(int argc, char** argv) { (void)argc; (void)argv; + shm_wrapper mem_("ps3eye-driver-shm", nullptr, sizeof(ps3eye::shm)); + volatile auto& ptr_ = *(ps3eye::shm*)mem_.ptr(); + volatile auto& in = ptr_.in; + volatile auto& out = ptr_.out; + + auto cameras = ps3eye::list_devices(); + + out.status_ = ps3eye::shm_out::status::starting; + + if (cameras.empty()) + error(out, "no camera found"); + + auto& camera = cameras[0]; + camera->set_debug(false); + auto* frame = (uint8_t*)out.data_640x480; + decltype(out.timecode) timecode = 0; + + { + int framerate = in.framerate; + if (framerate <= 0) + framerate = 60; + + if (!camera->init(get_mode(in.resolution), framerate)) + error(out, "camera init failed: %s", camera->error_string()); + + update_settings(*camera, in); + + if (!camera->start()) + error(out, "can't start camera: %s", camera->error_string()); + } + + out.timecode = 0; + in.do_exit = false; + std::atomic_thread_fence(std::memory_order_seq_cst); + + for (;;) + { + { + auto cookie = in.settings_updated; + if (cookie != out.settings_updated_ack) + { + camera->stop(); + update_settings(*camera, in); + int framerate = in.framerate; + if (framerate <= 0) + framerate = 60; + if (!camera->init(get_mode(in.resolution), framerate)) + error(out, "camera init failed: %s", camera->error_string()); + if (!camera->start()) + error(out, "can't start camera: %s", camera->error_string()); + out.settings_updated_ack = cookie; + } + } + + if (!camera->get_frame(frame)) + continue; + + out.timecode = ++timecode; + + if (in.do_exit) + break; + + std::atomic_thread_fence(std::memory_order_seq_cst); + } + return 0; } |