diff options
28 files changed, 497 insertions, 143 deletions
| diff --git a/api/plugin-support.hpp b/api/plugin-support.hpp index df1344bf..65b8e10d 100644 --- a/api/plugin-support.hpp +++ b/api/plugin-support.hpp @@ -35,10 +35,11 @@ struct dylib final          Tracker = 0xcafebeef,          Protocol = 0xdeadf00d,          Extension = 0xcafebabe, +        Video = 0xbadf00d,          Invalid = (unsigned)-1,      }; -    dylib(const QString& filename_, Type t) : +    dylib(const QString& filename_, Type t, bool load = true) :          full_filename(filename_),          module_name(trim_filename(filename_))      { @@ -57,19 +58,25 @@ struct dylib final          if (check(!handle.load()))              return; -        if (check((Dialog = (module_ctor_t) handle.resolve("GetDialog"), !Dialog))) -            return; +        if (load) +        { +            if (check((Dialog = (module_ctor_t) handle.resolve("GetDialog"), !Dialog))) +                return; -        if (check((Constructor = (module_ctor_t) handle.resolve("GetConstructor"), !Constructor))) -            return; +            if (check((Constructor = (module_ctor_t) handle.resolve("GetConstructor"), !Constructor))) +                return; -        if (check((Meta = (module_metadata_t) handle.resolve("GetMetadata"), !Meta))) -            return; +            if (check((Meta = (module_metadata_t) handle.resolve("GetMetadata"), !Meta))) +                return; + +            std::unique_ptr<Metadata_> m{Meta()}; -        std::unique_ptr<Metadata_> m{Meta()}; +            if (check(!m)) +                return; -        icon = m->icon(); -        name = m->name(); +            icon = m->icon(); +            name = m->name(); +        }          type = t;  #ifdef __clang__ @@ -88,18 +95,20 @@ struct dylib final          const struct filter_ {              Type type{Invalid};              QString glob; +            bool load = true;          } filters[] = {              { Filter, QStringLiteral(OPENTRACK_LIBRARY_PREFIX "opentrack-filter-*." OPENTRACK_LIBRARY_EXTENSION), },              { Tracker, QStringLiteral(OPENTRACK_LIBRARY_PREFIX "opentrack-tracker-*." OPENTRACK_LIBRARY_EXTENSION), },              { Protocol, QStringLiteral(OPENTRACK_LIBRARY_PREFIX "opentrack-proto-*." OPENTRACK_LIBRARY_EXTENSION), },              { Extension, QStringLiteral(OPENTRACK_LIBRARY_PREFIX "opentrack-ext-*." OPENTRACK_LIBRARY_EXTENSION), }, +            { Video, QStringLiteral(OPENTRACK_LIBRARY_PREFIX "opentrack-video-*." OPENTRACK_LIBRARY_EXTENSION), false, },          };          for (const filter_& filter : filters)          {              for (const QString& filename : module_directory.entryList({ filter.glob }, QDir::Files, QDir::Name))              { -                auto lib = std::make_shared<dylib>(QStringLiteral("%1/%2").arg(library_path, filename), filter.type); +                auto lib = std::make_shared<dylib>(QStringLiteral("%1/%2").arg(library_path, filename), filter.type, filter.load);                  if (lib->type == Invalid)                      continue; @@ -159,6 +168,7 @@ private:                      OPENTRACK_LIBRARY_PREFIX "opentrack-proto-",                      OPENTRACK_LIBRARY_PREFIX "opentrack-filter-",                      OPENTRACK_LIBRARY_PREFIX "opentrack-ext-", +                    OPENTRACK_LIBRARY_PREFIX "opentrack-video-",                  };                  for (auto name : names) @@ -198,7 +208,8 @@ struct Modules final          filter_modules(filter(dylib::Filter)),          tracker_modules(filter(dylib::Tracker)),          protocol_modules(filter(dylib::Protocol)), -        extension_modules(filter(dylib::Extension)) +        extension_modules(filter(dylib::Extension)), +        video_modules(filter(dylib::Video))      {}      dylib_list& filters() { return filter_modules; }      dylib_list& trackers() { return tracker_modules; } @@ -211,6 +222,7 @@ private:      dylib_list tracker_modules;      dylib_list protocol_modules;      dylib_list extension_modules; +    dylib_list video_modules;      static dylib_list& sorted(dylib_list& xs)      { diff --git a/tracker-aruco/ftnoir_tracker_aruco.cpp b/tracker-aruco/ftnoir_tracker_aruco.cpp index 8928566f..d9674755 100644 --- a/tracker-aruco/ftnoir_tracker_aruco.cpp +++ b/tracker-aruco/ftnoir_tracker_aruco.cpp @@ -6,8 +6,6 @@   */  #include "ftnoir_tracker_aruco.h" -#include "cv/video-property-page.hpp" -#include "compat/camera-names.hpp"  #include "compat/sleep.hpp"  #include "compat/math-imports.hpp" @@ -75,7 +73,6 @@ aruco_tracker::~aruco_tracker()      wait();      // fast start/stop causes breakage      portable::sleep(1000); -    camera.release();  }  module_status aruco_tracker::start_tracker(QFrame* videoframe) @@ -166,16 +163,18 @@ bool aruco_tracker::open_camera()      QMutexLocker l(&camera_mtx); -    camera = cv::VideoCapture(camera_name_to_index(s.camera_name)); +    camera = video::make_camera(s.camera_name); +    video::impl::camera::info args {}; +      if (res.width)      { -        camera.set(cv::CAP_PROP_FRAME_WIDTH, res.width); -        camera.set(cv::CAP_PROP_FRAME_HEIGHT, res.height); +        args.width = res.width; +        args.height = res.height;      }      if (fps) -        camera.set(cv::CAP_PROP_FPS, fps); +        args.fps = fps; -    if (!camera.isOpened()) +    if (!camera->start(args))      {          qDebug() << "aruco tracker: can't open camera";          return false; @@ -372,14 +371,28 @@ void aruco_tracker::run()          {              QMutexLocker l(&camera_mtx); -            if (!camera.read(color)) +            auto [ img, res ] = camera->get_frame(); + +            if (!res)              {                  portable::sleep(100);                  continue;              } -        } -        cv::cvtColor(color, grayscale, cv::COLOR_BGR2GRAY); +            color = cv::Mat(img.height, img.width, CV_8UC(img.channels), (void*)img.data, img.stride); + +            switch (img.channels) +            { +            case 1: +                grayscale.setTo(color); break; +            case 3: +                cv::cvtColor(color, grayscale, cv::COLOR_BGR2GRAY); +                break; +            default: +                qDebug() << "aruco: can't handle" << img.channels << "color channels"; +                return; +            } +        }  #ifdef DEBUG_UNSHARP_MASKING          { @@ -496,7 +509,9 @@ aruco_dialog::aruco_dialog() :      tracker = nullptr;      calib_timer.setInterval(100); -    ui.cameraName->addItems(get_camera_names()); + +    for (const auto& str : video::camera_names()) +        ui.cameraName->addItem(str);      tie_setting(s.camera_name, ui.cameraName);      tie_setting(s.resolution, ui.resolution); @@ -572,10 +587,10 @@ void aruco_dialog::camera_settings()      if (tracker)      {          QMutexLocker l(&tracker->camera_mtx); -        video_property_page::show_from_capture(tracker->camera, camera_name_to_index(s.camera_name)); +        (void)tracker->camera->show_dialog();      }      else -        video_property_page::show(camera_name_to_index(s.camera_name)); +        (void)video::show_dialog(s.camera_name);  }  void aruco_dialog::update_camera_settings_state(const QString& name) diff --git a/tracker-aruco/ftnoir_tracker_aruco.h b/tracker-aruco/ftnoir_tracker_aruco.h index 1d6fd107..0a33f02b 100644 --- a/tracker-aruco/ftnoir_tracker_aruco.h +++ b/tracker-aruco/ftnoir_tracker_aruco.h @@ -13,6 +13,7 @@  #include "api/plugin-api.hpp"  #include "cv/video-widget.hpp"  #include "compat/timer.hpp" +#include "video/camera.hpp"  #include "aruco/markerdetector.h" @@ -27,7 +28,6 @@  #include <cinttypes>  #include <opencv2/core.hpp> -#include <opencv2/videoio.hpp>  // value 0->1  //#define DEBUG_UNSHARP_MASKING .75 @@ -77,7 +77,7 @@ public:      void getRT(cv::Matx33d &r, cv::Vec3d &t);      QMutex camera_mtx; -    cv::VideoCapture camera; +    std::unique_ptr<video::impl::camera> camera;  private:      bool detect_with_roi(); diff --git a/tracker-pt/CMakeLists.txt b/tracker-pt/CMakeLists.txt index f12f530b..304a6b3d 100644 --- a/tracker-pt/CMakeLists.txt +++ b/tracker-pt/CMakeLists.txt @@ -2,7 +2,7 @@ find_package(OpenCV QUIET)  if(OpenCV_FOUND)      otr_module(tracker-pt-base STATIC)      target_include_directories(${self} SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS}) -    target_link_libraries(${self} opencv_imgproc opentrack-cv opencv_core) +    target_link_libraries(${self} opencv_imgproc opentrack-cv opencv_core opentrack-video)      set_property(TARGET ${self} PROPERTY OUTPUT_NAME "pt-base")  endif()  add_subdirectory(module) diff --git a/tracker-pt/ftnoir_tracker_pt.cpp b/tracker-pt/ftnoir_tracker_pt.cpp index 3854e531..4b796af7 100644 --- a/tracker-pt/ftnoir_tracker_pt.cpp +++ b/tracker-pt/ftnoir_tracker_pt.cpp @@ -8,7 +8,6 @@  #include "ftnoir_tracker_pt.h"  #include "video/video-widget.hpp" -#include "compat/camera-names.hpp"  #include "compat/math-imports.hpp"  #include "pt-api.hpp" @@ -121,7 +120,7 @@ bool Tracker_PT::maybe_reopen_camera()  {      QMutexLocker l(&camera_mtx); -    return camera->start(camera_name_to_index(s.camera_name), +    return camera->start(s.camera_name,                           s.cam_fps, s.cam_res_x, s.cam_res_y);  } diff --git a/tracker-pt/ftnoir_tracker_pt_dialog.cpp b/tracker-pt/ftnoir_tracker_pt_dialog.cpp index 2b06c823..edf689a9 100644 --- a/tracker-pt/ftnoir_tracker_pt_dialog.cpp +++ b/tracker-pt/ftnoir_tracker_pt_dialog.cpp @@ -7,10 +7,9 @@   */  #include "ftnoir_tracker_pt_dialog.h" -  #include "compat/math.hpp" -#include "compat/camera-names.hpp" -#include "cv/video-property-page.hpp" +#include "video/camera.hpp" +  #include <opencv2/core.hpp>  #include <QString> @@ -33,7 +32,8 @@ TrackerDialog_PT::TrackerDialog_PT(const QString& module_name) :      ui.setupUi(this); -    ui.camdevice_combo->addItems(get_camera_names()); +    for (const QString& str : video::camera_names()) +        ui.camdevice_combo->addItem(str);      tie_setting(s.camera_name, ui.camdevice_combo);      tie_setting(s.cam_res_x, ui.res_x_spin); @@ -231,10 +231,7 @@ void TrackerDialog_PT::show_camera_settings()          tracker->camera->show_camera_settings();      }      else -    { -        const int idx = camera_name_to_index(s.camera_name); -        video_property_page::show(idx); -    } +        (void)video::show_dialog(s.camera_name);  }  void TrackerDialog_PT::trans_calib_step() diff --git a/tracker-pt/module/camera.cpp b/tracker-pt/module/camera.cpp index 1afecc92..687f5bff 100644 --- a/tracker-pt/module/camera.cpp +++ b/tracker-pt/module/camera.cpp @@ -8,15 +8,9 @@  #include "camera.h"  #include "frame.hpp" -#include "compat/sleep.hpp" -#include "compat/camera-names.hpp"  #include "compat/math-imports.hpp" -#include <opencv2/imgproc.hpp> - -#include "cv/video-property-page.hpp" - -#include <cstdlib> +#include <opencv2/core.hpp>  namespace pt_module { @@ -26,22 +20,18 @@ Camera::Camera(const QString& module_name) : s { module_name }  QString Camera::get_desired_name() const  { -    return desired_name; +    return cam_desired.name;  }  QString Camera::get_active_name() const  { -    return active_name; +    return cam_info.name;  }  void Camera::show_camera_settings()  { -    const int idx = camera_name_to_index(s.camera_name); - -    if (cap && cap->isOpened()) -        video_property_page::show_from_capture(*cap, idx); -    else -        video_property_page::show(idx); +    if (cap) +        (void)cap->show_dialog();  }  Camera::result Camera::get_info() const @@ -83,59 +73,53 @@ Camera::result Camera::get_frame(pt_frame& frame_)          return { false, {} };  } -bool Camera::start(int idx, int fps, int res_x, int res_y) +bool Camera::start(const QString& name, int fps, int res_x, int res_y)  { -    if (idx >= 0 && fps >= 0 && res_x >= 0 && res_y >= 0) +    if (fps >= 0 && res_x >= 0 && res_y >= 0)      { -        if (cam_desired.idx != idx || +        if (cam_desired.name != name ||              (int)cam_desired.fps != fps ||              cam_desired.res_x != res_x ||              cam_desired.res_y != res_y || -            !cap || !cap->isOpened() || !cap->grab()) +            !cap || !cap->is_open())          {              stop(); -            desired_name = get_camera_names().value(idx); -            cam_desired.idx = idx; +            cam_desired.name = name;              cam_desired.fps = fps;              cam_desired.res_x = res_x;              cam_desired.res_y = res_y;              cam_desired.fov = fov; -            cap = camera_ptr(new cv::VideoCapture(idx)); +            cap = video::make_camera(name); -            if (cam_desired.res_x > 0 && cam_desired.res_y > 0) -            { -                cap->set(cv::CAP_PROP_FRAME_WIDTH,  res_x); -                cap->set(cv::CAP_PROP_FRAME_HEIGHT, res_y); -            } +            if (!cap) +                goto fail; -            if (fps > 0) -                cap->set(cv::CAP_PROP_FPS, fps); +            camera::info info {}; +            info.fps = fps; +            info.width = res_x; +            info.height = res_y; -            if (cap->isOpened()) -            { -                cam_info = pt_camera_info(); -                cam_info.idx = idx; -                dt_mean = 0; -                active_name = desired_name; +            if (!cap->start(info)) +                goto fail; -                cv::Mat tmp; +            cam_info = pt_camera_info(); +            cam_info.name = name; +            dt_mean = 0; -                if (get_frame_(tmp)) -                { -                    t.start(); -                    return true; -                } -            } +            cv::Mat tmp; -            cap = nullptr; -            return false; -        } +            if (!get_frame_(tmp)) +                goto fail; -        return true; +            t.start(); +        }      } +    return true; + +fail:      stop();      return false;  } @@ -143,34 +127,23 @@ bool Camera::start(int idx, int fps, int res_x, int res_y)  void Camera::stop()  {      cap = nullptr; -    desired_name = QString{}; -    active_name = QString{};      cam_info = {};      cam_desired = {};  } -bool Camera::get_frame_(cv::Mat& frame) +bool Camera::get_frame_(cv::Mat& img)  { -    if (cap && cap->isOpened()) +    if (cap && cap->is_open())      { -        for (unsigned i = 0; i < 10; i++) +        auto [ frame, ret ] = cap->get_frame(); +        if (ret)          { -            if (cap->read(frame)) -                return true; -            portable::sleep(50); +            img = cv::Mat(frame.height, frame.width, CV_8UC(frame.channels), (void*)frame.data, frame.stride); +            return true;          }      } -    return false; -} -void Camera::camera_deleter::operator()(cv::VideoCapture* cap) -{ -    if (cap) -    { -        if (cap->isOpened()) -            cap->release(); -        delete cap; -    } +    return false;  }  } // ns pt_module diff --git a/tracker-pt/module/camera.h b/tracker-pt/module/camera.h index 2ea633d0..02e2fe4d 100644 --- a/tracker-pt/module/camera.h +++ b/tracker-pt/module/camera.h @@ -9,11 +9,11 @@  #include "pt-api.hpp"  #include "compat/timer.hpp" +#include "video/camera.hpp"  #include <memory>  #include <opencv2/core.hpp> -#include <opencv2/videoio.hpp>  #include <QString> @@ -23,7 +23,7 @@ struct Camera final : pt_camera  {      Camera(const QString& module_name); -    bool start(int idx, int fps, int res_x, int res_y) override; +    bool start(const QString& name, int fps, int res_x, int res_y) override;      void stop() override;      result get_frame(pt_frame& Frame) override; @@ -37,23 +37,16 @@ struct Camera final : pt_camera      void show_camera_settings() override;  private: +    using camera = typename video::impl::camera; +      [[nodiscard]] bool get_frame_(cv::Mat& frame);      f dt_mean = 0, fov = 30;      Timer t;      pt_camera_info cam_info;      pt_camera_info cam_desired; -    QString desired_name, active_name; - -    struct camera_deleter final -    { -        void operator()(cv::VideoCapture* cap); -    }; - -    using camera_ptr = std::unique_ptr<cv::VideoCapture, camera_deleter>; - -    camera_ptr cap; +    std::unique_ptr<camera> cap;      pt_settings s;      static constexpr f dt_eps = f{1}/256; diff --git a/tracker-pt/module/point_extractor.cpp b/tracker-pt/module/point_extractor.cpp index 298d8752..2cb5db97 100644 --- a/tracker-pt/module/point_extractor.cpp +++ b/tracker-pt/module/point_extractor.cpp @@ -13,8 +13,6 @@  #include "cv/numeric.hpp"  #include "compat/math.hpp" -#include <opencv2/videoio.hpp> -  #undef PREVIEW  //#define PREVIEW diff --git a/tracker-pt/pt-api.hpp b/tracker-pt/pt-api.hpp index b44cfea2..741576a1 100644 --- a/tracker-pt/pt-api.hpp +++ b/tracker-pt/pt-api.hpp @@ -12,6 +12,7 @@  #include <opencv2/core.hpp>  #include <QImage> +#include <QString>  #ifdef __clang__  #   pragma clang diagnostic push @@ -30,7 +31,7 @@ struct pt_camera_info final      int res_x = 0;      int res_y = 0; -    int idx = -1; +    QString name;  };  struct pt_pixel_pos_mixin @@ -74,7 +75,7 @@ struct pt_camera      pt_camera();      virtual ~pt_camera(); -    [[nodiscard]] virtual bool start(int idx, int fps, int res_x, int res_y) = 0; +    [[nodiscard]] virtual bool start(const QString& name, int fps, int res_x, int res_y) = 0;      virtual void stop() = 0;      virtual result get_frame(pt_frame& frame) = 0; diff --git a/tracker-wii/wii_camera.cpp b/tracker-wii/wii_camera.cpp index 90ad6385..97a32b9f 100644 --- a/tracker-wii/wii_camera.cpp +++ b/tracker-wii/wii_camera.cpp @@ -16,13 +16,10 @@  #include "wii_frame.hpp"  #include "compat/sleep.hpp" -#include "compat/camera-names.hpp"  #include "compat/math-imports.hpp"  #include <opencv2/imgproc.hpp> -#include "cv/video-property-page.hpp" -  #include <bluetoothapis.h>  using namespace pt_module; @@ -33,7 +30,7 @@ WIICamera::WIICamera(const QString& module_name) : s { module_name }  	cam_info.res_x = 1024;  	cam_info.res_y = 768;  	cam_info.fov = 42.0f; -    cam_info.idx = 0; +	cam_info.name = "Wii";  }  WIICamera::~WIICamera() @@ -86,7 +83,7 @@ WIICamera::result WIICamera::get_frame(pt_frame& frame_)  	return result(true, cam_info);  } -bool WIICamera::start(int idx, int fps, int res_x, int res_y) +bool WIICamera::start(const QString& name, int fps, int res_x, int res_y)  {  	m_pDev = std::make_unique<wiimote>();  	m_pDev->ChangedCallback = on_state_change; diff --git a/tracker-wii/wii_camera.h b/tracker-wii/wii_camera.h index 05f5436c..7bc74559 100644 --- a/tracker-wii/wii_camera.h +++ b/tracker-wii/wii_camera.h @@ -17,7 +17,6 @@  #include <tuple>  #include <opencv2/core.hpp> -#include <opencv2/videoio.hpp>  #include <QString> @@ -31,7 +30,7 @@ struct WIICamera final : pt_camera      WIICamera(const QString& module_name);      ~WIICamera() override; -    bool start(int idx, int fps, int res_x, int res_y) override; +    bool start(const QString& name, int fps, int res_x, int res_y) override;      void stop() override;      result get_frame(pt_frame& Frame) override; diff --git a/tracker-wii/wii_point_extractor.cpp b/tracker-wii/wii_point_extractor.cpp index a23e0e5b..89e4b41b 100644 --- a/tracker-wii/wii_point_extractor.cpp +++ b/tracker-wii/wii_point_extractor.cpp @@ -14,8 +14,6 @@  #include "cv/numeric.hpp"  #include "compat/math.hpp" -#include <opencv2/videoio.hpp> -  #undef PREVIEW  //#define PREVIEW diff --git a/variant/default/_variant.cmake b/variant/default/_variant.cmake index 161fefda..7501b0a4 100644 --- a/variant/default/_variant.cmake +++ b/variant/default/_variant.cmake @@ -24,6 +24,7 @@ function(otr_init_variant)          "migration"          "main-window"          "video" +        "video-*"      )      set_property(GLOBAL PROPERTY opentrack-subprojects "${subprojects}") diff --git a/variant/default/main-window.cpp b/variant/default/main-window.cpp index a223c32f..334695cb 100644 --- a/variant/default/main-window.cpp +++ b/variant/default/main-window.cpp @@ -448,7 +448,7 @@ void main_window::stop_tracker_()      with_tracker_teardown sentinel;      pose_update_timer.stop(); -    ui.pose_display->rotate_sync(0,0,0, 0,0,0); +    ui.pose_display->present(0,0,0, 0,0,0);      if (pTrackerDialog)          pTrackerDialog->unregister_tracker(); @@ -473,8 +473,8 @@ void main_window::stop_tracker_()  void main_window::show_pose_(const double* mapped, const double* raw)  { -    ui.pose_display->rotate_async(mapped[Yaw], mapped[Pitch], -mapped[Roll], -                                  mapped[TX], mapped[TY], mapped[TZ]); +    ui.pose_display->present(mapped[Yaw], mapped[Pitch], -mapped[Roll], +                             mapped[TX], mapped[TY], mapped[TZ]);      QLCDNumber* raw_[] = {          ui.raw_x, ui.raw_y, ui.raw_z, diff --git a/video-opencv/CMakeLists.txt b/video-opencv/CMakeLists.txt new file mode 100644 index 00000000..d8b9b896 --- /dev/null +++ b/video-opencv/CMakeLists.txt @@ -0,0 +1,6 @@ +find_package(OpenCV QUIET) + +if(OpenCV_FOUND) +    otr_module(video-opencv) +    target_link_libraries(${self} opencv_core opencv_videoio opentrack-video) +endif() diff --git a/video-opencv/camera-impl.cpp b/video-opencv/camera-impl.cpp new file mode 100644 index 00000000..ca18fd4b --- /dev/null +++ b/video-opencv/camera-impl.cpp @@ -0,0 +1,173 @@ +/* Copyright (c) 2019 Stanislaw Halik <sthalik@misaki.pl> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "compat/sleep.hpp" +#include "video/camera.hpp" + +#include "camera-names.hpp" +#include "video-property-page.hpp" + +#include <optional> + +#include <opencv2/core.hpp> +#include <opencv2/videoio.hpp> + +using namespace video::impl; + +struct cam; + +struct metadata : camera_ +{ +    metadata(); +    std::vector<QString> camera_names() const override; +    std::unique_ptr<camera> make_camera(const QString& name) override; +    bool can_show_dialog(const QString& camera_name) override; +    bool show_dialog(const QString& camera_name) override; +}; + +struct cam final : camera +{ +    cam(int idx); +    ~cam() override; + +    bool start(const info& args) override; +    void stop() override; +    bool is_open() override; +    std::tuple<const frame&, bool> get_frame() override; +    bool show_dialog() override; + +    bool get_frame_(); + +    std::optional<cv::VideoCapture> cap; +    cv::Mat mat; +    frame frame_; +    int idx = -1; +}; + +metadata::metadata() = default; + +std::unique_ptr<camera> metadata::make_camera(const QString& name) +{ +    int idx = camera_name_to_index(name); +    if (idx != -1) +        return std::make_unique<cam>(idx); +    else +        return nullptr; +} + +std::vector<QString> metadata::camera_names() const +{ +    return get_camera_names(); +} + +bool metadata::can_show_dialog(const QString& camera_name) +{ +    return camera_name_to_index(camera_name) != -1; +} + +bool metadata::show_dialog(const QString& camera_name) +{ +    int idx = camera_name_to_index(camera_name); +    if (idx != -1) +    { +        video_property_page::show(idx); +        return true; +    } +    else +        return false; +} + +cam::cam(int idx) : idx(idx) +{ +} + +cam::~cam() +{ +    stop(); +} + +void cam::stop() +{ +    if (cap) +    { +        if (cap->isOpened()) +            cap->release(); +        cap = std::nullopt; +    } +    mat = cv::Mat(); +    frame_ = { {}, false }; +} + +bool cam::is_open() +{ +    return !!cap; +} + +bool cam::start(const info& args) +{ +    stop(); +    cap.emplace(idx); + +    if (args.width > 0 && args.height > 0) +    { +        cap->set(cv::CAP_PROP_FRAME_WIDTH,  args.width); +        cap->set(cv::CAP_PROP_FRAME_HEIGHT, args.height); +    } +    if (args.fps > 0) +        cap->set(cv::CAP_PROP_FPS, args.fps); + +    if (!cap->isOpened()) +        goto fail; + +    if (!get_frame_()) +        goto fail; + +    return true; + +fail: +    stop(); +    return false; +} + +bool cam::get_frame_() +{ +    if (!is_open()) +        return false; + +    for (unsigned i = 0; i < 10; i++) +    { +        if (cap->read(mat)) +        { +            frame_.data = mat.data; +            frame_.width = mat.cols; +            frame_.height = mat.rows; +            frame_.stride = mat.step.p[0]; +            frame_.channels = mat.channels(); + +            return true; +        } +        portable::sleep(50); +    } + +    return false; +} + +std::tuple<const frame&, bool> cam::get_frame() +{ +    bool ret = get_frame_(); +    return { frame_, ret }; +} + +bool cam::show_dialog() +{ +    if (is_open()) +        return video_property_page::show_from_capture(*cap, idx); +    else +        return video_property_page::show(idx); +} + +OTR_REGISTER_CAMERA(metadata) diff --git a/compat/camera-names.cpp b/video-opencv/camera-names.cpp index 246d76ee..69926e5a 100644 --- a/compat/camera-names.cpp +++ b/video-opencv/camera-names.cpp @@ -1,5 +1,8 @@  #include "camera-names.hpp" +#include <algorithm> +#include <iterator> +  #ifdef _WIN32  #   include <cwchar>  #   define NO_DSHOW_STRSAFE @@ -21,15 +24,16 @@  int camera_name_to_index(const QString &name)  {      auto list = get_camera_names(); -    int ret = list.indexOf(name); -    if (ret < 0) -        ret = 0; -    return ret; +    auto it = std::find(list.cbegin(), list.cend(), name); +    if (it != list.cend()) +        return std::distance(list.cbegin(), it); + +    return -1;  } -QList<QString> get_camera_names() +std::vector<QString> get_camera_names()  { -    QList<QString> ret; +    std::vector<QString> ret;  #ifdef _WIN32      // Create the System Device Enumerator.      HRESULT hr; @@ -62,7 +66,7 @@ QList<QString> get_camera_names()                  {                      // Display the name in your UI somehow.                      QString str((QChar*)var.bstrVal, int(std::wcslen(var.bstrVal))); -                    ret.append(str); +                    ret.push_back(str);                  }                  VariantClear(&var);                  pPropBag->Release(); @@ -93,7 +97,7 @@ QList<QString> get_camera_names()                  close(fd);                  continue;              } -            ret.append(QString{(const char*)video_cap.card}); +            ret.push_back(QString((const char*)video_cap.card));              close(fd);          }      } diff --git a/compat/camera-names.hpp b/video-opencv/camera-names.hpp index 97184c8c..9f0883f5 100644 --- a/compat/camera-names.hpp +++ b/video-opencv/camera-names.hpp @@ -8,11 +8,11 @@  #pragma once -#include <QList> +#include <vector>  #include <QString>  #include "export.hpp" -OTR_COMPAT_EXPORT QList<QString> get_camera_names(); -OTR_COMPAT_EXPORT int camera_name_to_index(const QString &name); +std::vector<QString> get_camera_names(); +int camera_name_to_index(const QString &name); diff --git a/video-opencv/export.hpp b/video-opencv/export.hpp new file mode 100644 index 00000000..1d43a9f1 --- /dev/null +++ b/video-opencv/export.hpp @@ -0,0 +1,11 @@ +// generates export.hpp for each module from compat/linkage.hpp + +#pragma once + +#include "compat/linkage-macros.hpp" + +#ifdef BUILD_VIDEO_OPENCV +#   define OTR_VIDEO_OPENCV_EXPORT OTR_GENERIC_EXPORT +#else +#   define OTR_VIDEO_OPENCV_EXPORT OTR_GENERIC_IMPORT +#endif diff --git a/video-opencv/lang/nl_NL.ts b/video-opencv/lang/nl_NL.ts new file mode 100644 index 00000000..6401616d --- /dev/null +++ b/video-opencv/lang/nl_NL.ts @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +</TS> diff --git a/video-opencv/lang/ru_RU.ts b/video-opencv/lang/ru_RU.ts new file mode 100644 index 00000000..6401616d --- /dev/null +++ b/video-opencv/lang/ru_RU.ts @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +</TS> diff --git a/video-opencv/lang/stub.ts b/video-opencv/lang/stub.ts new file mode 100644 index 00000000..6401616d --- /dev/null +++ b/video-opencv/lang/stub.ts @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +</TS> diff --git a/video-opencv/lang/zh_CN.ts b/video-opencv/lang/zh_CN.ts new file mode 100644 index 00000000..6401616d --- /dev/null +++ b/video-opencv/lang/zh_CN.ts @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +</TS> diff --git a/cv/video-property-page.cpp b/video-opencv/video-property-page.cpp index bae5e8b3..92abd887 100644 --- a/cv/video-property-page.cpp +++ b/video-opencv/video-property-page.cpp @@ -9,7 +9,7 @@  #ifdef _WIN32 -#include "compat/camera-names.hpp" +#include "camera-names.hpp"  #include "compat/sleep.hpp"  #include "compat/run-in-thread.hpp"  #include "compat/library-path.hpp" diff --git a/cv/video-property-page.hpp b/video-opencv/video-property-page.hpp index c2b9525d..c2b9525d 100644 --- a/cv/video-property-page.hpp +++ b/video-opencv/video-property-page.hpp diff --git a/video/camera.cpp b/video/camera.cpp new file mode 100644 index 00000000..c33ab13a --- /dev/null +++ b/video/camera.cpp @@ -0,0 +1,66 @@ +#include "camera.hpp" + +#include <algorithm> +#include <utility> +#include <QMutex> + +static std::vector<std::unique_ptr<video::impl::camera_>> metadata; +static QMutex mtx; + +namespace video::impl { + +camera_::camera_() = default; +camera_::~camera_() = default; + +camera::camera() = default; +camera::~camera() = default; + +void register_camera(std::unique_ptr<impl::camera_> camera) +{ +    QMutexLocker l(&mtx); +    metadata.push_back(std::move(camera)); +} + +} // ns video::impl + +namespace video { + +bool show_dialog(const QString& camera_name) +{ +    QMutexLocker l(&mtx); + +    for (auto& camera : metadata) +        for (const QString& name : camera->camera_names()) +            if (name == camera_name) +                return camera->show_dialog(camera_name); + +    return false; +} + +std::unique_ptr<camera_impl> make_camera(const QString& name) +{ +    QMutexLocker l(&mtx); + +    for (auto& camera : metadata) +        for (const QString& name_ : camera->camera_names()) +            if (name_ == name) +                return camera->make_camera(name); + +    return nullptr; +} + +std::vector<QString> camera_names() +{ +    QMutexLocker l(&mtx); +    std::vector<QString> names; names.reserve(32); + +    for (auto& camera : metadata) +        for (const QString& name : camera->camera_names()) +            if (std::find(names.cbegin(), names.cend(), name) == names.cend()) +                names.push_back(name); + +    std::sort(names.begin(), names.end()); +    return names; +} + +} // ns video diff --git a/video/camera.hpp b/video/camera.hpp new file mode 100644 index 00000000..c9577933 --- /dev/null +++ b/video/camera.hpp @@ -0,0 +1,95 @@ +/* Copyright (c) 2019 Stanislaw Halik <sthalik@misaki.pl> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#pragma once + +#include "export.hpp" + +#include <memory> +#include <vector> + +#include <QString> + +namespace video +{ + +struct frame final +{ +    unsigned char* data = nullptr; +    int width = 0, height = 0, stride = 0, channels = 0; +}; + +} // ns video + +namespace video::impl { + +using namespace video; + +struct camera; + +struct OTR_VIDEO_EXPORT camera_ +{ +    camera_(); +    virtual ~camera_(); + +    virtual std::vector<QString> camera_names() const = 0; +    virtual std::unique_ptr<camera> make_camera(const QString& name) = 0; +    [[nodiscard]] virtual bool show_dialog(const QString& camera_name) = 0; +    virtual bool can_show_dialog(const QString& camera_name) = 0; +}; + +struct OTR_VIDEO_EXPORT camera +{ +    struct info final +    { +        int width = 0, height = 0, fps = 0; +    }; + +    camera(); +    virtual ~camera(); + +    [[nodiscard]] virtual bool start(const 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; +}; + +OTR_VIDEO_EXPORT +void register_camera(std::unique_ptr<impl::camera_> metadata); + +} // ns video::impl + +#define OTR_REGISTER_CAMERA2(type, ctr)                                     \ +    namespace {                                                             \ +        struct init_##ctr                                                   \ +        {                                                                   \ +            static char fuzz;                                               \ +        };                                                                  \ +        char init_##ctr :: fuzz =                                           \ +            (::video::impl::register_camera(std::make_unique<type>()), 0);  \ +    } // anon ns + +#define OTR_REGISTER_CAMERA(type)                                           \ +    OTR_REGISTER_CAMERA2(type, __COUNTER__) + +namespace video +{ +using camera_impl = typename impl::camera; + +OTR_VIDEO_EXPORT +std::unique_ptr<camera_impl> make_camera(const QString& name); + +OTR_VIDEO_EXPORT +std::vector<QString> camera_names(); + +[[nodiscard]] +OTR_VIDEO_EXPORT +bool show_dialog(const QString& camera_name); + +} // ns video | 
