summaryrefslogtreecommitdiffhomepage
path: root/video-ps3eye
diff options
context:
space:
mode:
Diffstat (limited to 'video-ps3eye')
-rw-r--r--video-ps3eye/CMakeLists.txt43
-rw-r--r--video-ps3eye/dialog.ui133
-rw-r--r--video-ps3eye/lang/nl_NL.ts19
-rw-r--r--video-ps3eye/lang/ru_RU.ts19
-rw-r--r--video-ps3eye/lang/stub.ts19
-rw-r--r--video-ps3eye/lang/zh_CN.ts19
-rw-r--r--video-ps3eye/module.cpp220
-rw-r--r--video-ps3eye/module.hpp91
m---------video-ps3eye/ps3eye-driver0
-rw-r--r--video-ps3eye/shm-layout.hpp27
-rw-r--r--video-ps3eye/shm.cxx2
-rw-r--r--video-ps3eye/shm.hpp4
-rw-r--r--video-ps3eye/wrapper.cxx110
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;
}