diff options
Diffstat (limited to 'video-ps3eye')
-rw-r--r-- | video-ps3eye/CMakeLists.txt | 69 | ||||
-rw-r--r-- | video-ps3eye/dialog.ui | 139 | ||||
-rw-r--r-- | video-ps3eye/lang/nl_NL.ts | 38 | ||||
-rw-r--r-- | video-ps3eye/lang/ru_RU.ts | 38 | ||||
-rw-r--r-- | video-ps3eye/lang/stub.ts | 38 | ||||
-rw-r--r-- | video-ps3eye/lang/zh_CN.ts | 38 | ||||
-rw-r--r-- | video-ps3eye/module.cpp | 307 | ||||
-rw-r--r-- | video-ps3eye/module.hpp | 82 | ||||
m--------- | video-ps3eye/ps3eye-driver | 0 | ||||
-rw-r--r-- | video-ps3eye/shm-layout.hpp | 39 | ||||
-rw-r--r-- | video-ps3eye/shm.cxx | 2 | ||||
-rw-r--r-- | video-ps3eye/shm.hpp | 4 | ||||
-rw-r--r-- | video-ps3eye/wrapper.cxx | 120 |
13 files changed, 914 insertions, 0 deletions
diff --git a/video-ps3eye/CMakeLists.txt b/video-ps3eye/CMakeLists.txt new file mode 100644 index 00000000..1f1780f9 --- /dev/null +++ b/video-ps3eye/CMakeLists.txt @@ -0,0 +1,69 @@ +add_compile_definitions(PS3EYE_DEBUG) + +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ps3eye-driver/CMakeLists.txt") + add_subdirectory("ps3eye-driver") + + if(NOT MSVC) + if(PKG_CONFIG_FOUND) + pkg_check_modules(libusb "libusb-1.0" QUIET) + endif() + 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 "") + if(SDK_LIBUSB) + set(libusb_FOUND TRUE) + link_directories("${SDK_LIBUSB}") + include_directories(SYSTEM "${SDK_LIBUSB}") + endif() + endif() +endif() + +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-libexec}") + break() + endif() + endforeach() + endif() +endif() + +if(TARGET ps3eye-mode-test) + 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() + set(vcrun "${SDK_LIBUSB}/vcruntime140.dll") + if(EXISTS "${vcrun}") + otr_install_lib("${vcrun}" "${opentrack-libexec}") + endif() + endif() +endif() + +if(TARGET ps3eye-frame-test) + 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..68060eb9 --- /dev/null +++ b/video-ps3eye/dialog.ui @@ -0,0 +1,139 @@ +<?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>124</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="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>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="Expanding" vsizetype="Preferred"> + <horstretch>0</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="Preferred"> + <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 new file mode 100644 index 00000000..f3a16fd4 --- /dev/null +++ b/video-ps3eye/lang/nl_NL.ts @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="nl_NL"> +<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> +<context> + <name>dialog</name> + <message> + <source>Can't open camera</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>PS3 Eye driver error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown error</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/video-ps3eye/lang/ru_RU.ts b/video-ps3eye/lang/ru_RU.ts new file mode 100644 index 00000000..1edcf50d --- /dev/null +++ b/video-ps3eye/lang/ru_RU.ts @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="ru_RU"> +<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> +<context> + <name>dialog</name> + <message> + <source>Can't open camera</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>PS3 Eye driver error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown error</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/video-ps3eye/lang/stub.ts b/video-ps3eye/lang/stub.ts new file mode 100644 index 00000000..81ffc826 --- /dev/null +++ b/video-ps3eye/lang/stub.ts @@ -0,0 +1,38 @@ +<?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> +<context> + <name>dialog</name> + <message> + <source>Can't open camera</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>PS3 Eye driver error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown error</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/video-ps3eye/lang/zh_CN.ts b/video-ps3eye/lang/zh_CN.ts new file mode 100644 index 00000000..9650c966 --- /dev/null +++ b/video-ps3eye/lang/zh_CN.ts @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="zh_CN"> +<context> + <name>Dialog</name> + <message> + <source>PS3 Eye</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Camera settings</source> + <translation>相机设置</translation> + </message> + <message> + <source>Exposure</source> + <translation>曝光</translation> + </message> + <message> + <source>Gain</source> + <translation>增益</translation> + </message> +</context> +<context> + <name>dialog</name> + <message> + <source>Can't open camera</source> + <translation>无法打开相机</translation> + </message> + <message> + <source>PS3 Eye driver error: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown error</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/video-ps3eye/module.cpp b/video-ps3eye/module.cpp new file mode 100644 index 00000000..02543082 --- /dev/null +++ b/video-ps3eye/module.cpp @@ -0,0 +1,307 @@ +#include "module.hpp" +#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; + libusb_device **list = nullptr; + ssize_t sz = 0; + int rc = 0, cnt = 0; + + constexpr int vendor_id = 0x1415; + constexpr int product_id = 0x2000; + + rc = libusb_init(&ctx); + + if (rc) + goto end; + + sz = libusb_get_device_list(ctx, &list); + + if (sz < 0) + goto end; + + for (int i = 0; i < sz; ++i) { + libusb_device *device = list[i]; + libusb_device_descriptor desc = {}; + + if (libusb_get_device_descriptor(device, &desc)) + goto end; + + if (desc.idVendor == vendor_id && desc.idProduct == product_id) + cnt++; + } + +end: + if (list) + libusb_free_device_list(list, 1); + if (ctx) + libusb_exit(ctx); + + 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"); + +std::vector<QString> ps3eye_camera_::camera_names() const +{ + if (check_device_exists()) + return { camera_name }; + else + return {}; +} +std::unique_ptr<camera> ps3eye_camera_::make_camera(const QString& name) +{ + if (name == camera_name && check_device_exists()) + return std::make_unique<ps3eye_camera>(); + else + return {}; +} + +static bool show_dialog_() +{ + auto& dlg = *new dialog; + dlg.setWindowFlag(Qt::MSWindowsFixedSizeDialogHint); + dlg.setAttribute(Qt::WA_DeleteOnClose); + dlg.adjustSize(); dlg.setFixedSize(dlg.size()); + dlg.show(); + return true; +} + +bool ps3eye_camera_::show_dialog(const QString&) +{ + return show_dialog_(); +} + +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\""); + // workaround apparent Qt 5.15.2 bug -sh 20210817 + wrapper.setProcessChannelMode(QProcess::ForwardedChannels); +#else + wrapper.setProgram("ps3eye-subprocess"); +#endif +} + +ps3eye_camera::~ps3eye_camera() +{ + stop(); +} + +void ps3eye_camera::stop() +{ + open = false; + + if (wrapper.state() != QProcess::NotRunning) + { + volatile auto& ptr = *(ps3eye::shm*)shm.ptr(); + ptr.in.do_exit = 1; + std::atomic_thread_fence(std::memory_order_seq_cst); + wrapper.waitForFinished(1000); + + if (wrapper.state() != QProcess::NotRunning) + wrapper.kill(); + wrapper.waitForFinished(1000); + } +} + +bool ps3eye_camera::start(info& args) +{ + if (!shm.success()) + return false; + + stop(); + + volatile auto& ptr = *(ps3eye::shm*)shm.ptr(); + QString error; + + using mode = ps3eye::shm_in::mode; + + open = false; + fr = {}; + fr.channels = args.num_channels == 1 ? 1 : 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; + ptr.in.channels = args.num_channels == 1 ? 1 : 3; + + sleep_ms = std::clamp(int(std::floor(450./ptr.in.framerate)), 1, 10); + + wrapper.start(); + + constexpr int sleep_ms = 10, max_sleeps = 2000/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 = QString{}; + 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, [error = std::move(error)] { + dialog::show_open_failure_msgbox(error); + }); + + 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); + t.setInterval(500); t.setSingleShot(true); + 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&) { t.stop(); t.start(); }); + connect(&s.gain, value_::value_changed<slider_value>(), this, [this](const slider_value&) { t.stop(); t.start(); }); + 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); + connect(&t, &QTimer::timeout, this, [this] { s.set_exposure(); s.set_gain(); }); +} +void dialog::show_open_failure_msgbox(const QString& error) +{ + const QString& error_ = error.isNull() ? tr("Unknown error") : error; + QMessageBox::critical(nullptr, + tr("Can't open camera"), + tr("PS3 Eye driver error: %1").arg(error_), + QMessageBox::Close); +} + +// 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 new file mode 100644 index 00000000..f6934d70 --- /dev/null +++ b/video-ps3eye/module.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include "video/camera.hpp" +#include "shm-layout.hpp" +#include "compat/shm.h" +#include "options/options.hpp" +#include "compat/macros.h" +#include "compat/timer.hpp" +#include "ui_dialog.h" + +#include <QDialog> +#include <QProcess> +#include <QTimer> + +using namespace options; + +using video::impl::camera; +using video::impl::camera_; +using video::frame; + +struct settings final +{ + 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}}; + + void set_exposure(); + void set_gain(); +}; + +class dialog final : public QWidget +{ + Q_OBJECT + Ui_Dialog ui; + settings s; + QTimer t{this}; + + 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(); if (t.isActive()) { s.set_exposure(); s.set_gain(); } } + +public: + explicit dialog(QWidget* parent = nullptr); + static void show_open_failure_msgbox(const QString& error); +}; + +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 * ps3eye::num_channels] = {}; + int framerate = 30, sleep_ms = 1; + bool open = false; + unsigned timecode = 0; + + ps3eye_camera(); + ~ps3eye_camera() override; + + 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; +}; + +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; +}; diff --git a/video-ps3eye/ps3eye-driver b/video-ps3eye/ps3eye-driver new file mode 160000 +Subproject fe4eef71669bc6365a651b3c734ebd2bb5f57f8 diff --git a/video-ps3eye/shm-layout.hpp b/video-ps3eye/shm-layout.hpp new file mode 100644 index 00000000..65b0a4f1 --- /dev/null +++ b/video-ps3eye/shm-layout.hpp @@ -0,0 +1,39 @@ +#pragma once +#include <cstdint> + +namespace ps3eye { + +static constexpr unsigned num_channels = 3; + +struct shm_in { + enum class mode : uint8_t { qvga, vga, }; + + uint32_t settings_updated; + uint8_t framerate, channels; + mode resolution; + //uint8_t sharpness, contrast, brightness hue, saturation; + uint8_t gain, exposure, auto_gain, test_pattern; + uint8_t do_exit; +}; + +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][num_channels]; + uint8_t data_640x480[640][480][num_channels]; + }; +}; + +struct alignas(64) shm { + shm_out out; + [[maybe_unused]] const char _padding[128 - sizeof(shm_out) % 128]; // NOLINT + shm_in in; +}; + +} // ns ps3eye 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 new file mode 100644 index 00000000..b7f58185 --- /dev/null +++ b/video-ps3eye/wrapper.cxx @@ -0,0 +1,120 @@ +#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; + int num_channels = in.channels; + + 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(true); + auto* frame = (uint8_t*)out.data_640x480; + decltype(out.timecode) timecode = 0; + + auto fmt = num_channels == 1 ? ps3eye::format::Gray : ps3eye::format::BGR; + + { + int framerate = in.framerate; + if (framerate <= 0) + framerate = 60; + + if (!camera->init(get_mode(in.resolution), framerate, fmt)) + 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, fmt)) + 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; +} |