diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bf8618..169bd04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,7 @@ set(MYNTEYE_SRCS ${UVC_SRC} src/internal/channels.cc src/internal/config.cc + src/internal/dl.cc src/internal/files.cc src/internal/motions.cc src/internal/streams.cc diff --git a/src/api/api.cc b/src/api/api.cc index cf3f364..e7b8f42 100644 --- a/src/api/api.cc +++ b/src/api/api.cc @@ -7,8 +7,10 @@ #include "mynteye/glog_init.h" #include "mynteye/utils.h" +#include "api/plugin.h" #include "api/synthetic.h" #include "device/device.h" +#include "internal/dl.h" MYNTEYE_BEGIN_NAMESPACE @@ -192,6 +194,23 @@ std::vector API::GetMotionDatas() { return datas; } +void API::EnablePlugin(const std::string &path) { + DL dl; + CHECK(dl.Open(path.c_str())) << "Open plugin failed: " << path; + + plugin_version_code_t *plugin_version_code = + dl.Sym("plugin_version_code"); + LOG(INFO) << "Enable plugin, version code: " << plugin_version_code(); + + plugin_create_t *plugin_create = dl.Sym("plugin_create"); + plugin_destroy_t *plugin_destroy = dl.Sym("plugin_destroy"); + + std::shared_ptr plugin(plugin_create(), plugin_destroy); + plugin->OnCreate(this); + + synthetic_->SetPlugin(plugin); +} + std::shared_ptr API::device() { return device_; } diff --git a/src/api/api.h b/src/api/api.h index 0e43de7..2bbac61 100644 --- a/src/api/api.h +++ b/src/api/api.h @@ -92,6 +92,8 @@ class MYNTEYE_API API { std::size_t max_size = std::numeric_limits::max()); std::vector GetMotionDatas(); + void EnablePlugin(const std::string &path); + std::shared_ptr device(); private: diff --git a/src/api/plugin.h b/src/api/plugin.h new file mode 100644 index 0000000..2788425 --- /dev/null +++ b/src/api/plugin.h @@ -0,0 +1,81 @@ +#ifndef MYNTEYE_PLUGIN_H_ // NOLINT +#define MYNTEYE_PLUGIN_H_ +#pragma once + +#include + +#include + +#include "mynteye/mynteye.h" + +#ifndef MYNTEYE_PLUGIN_VERSION_CODE +#define MYNTEYE_PLUGIN_VERSION_CODE 0 +#endif + +MYNTEYE_BEGIN_NAMESPACE + +class API; +class Object; + +class MYNTEYE_API Plugin { + public: + Plugin() = default; + virtual ~Plugin() = 0; + + virtual void OnCreate(API *api) { + api_ = api; + } + + virtual bool OnRectifyProcess(Object *const in, Object *const out) { + UNUSED(in) + UNUSED(out) + return false; + } + + virtual bool OnDisparityProcess(Object *const in, Object *const out) { + UNUSED(in) + UNUSED(out) + return false; + } + + virtual bool OnDisparityNormalizedProcess( + Object *const in, Object *const out) { + UNUSED(in) + UNUSED(out) + return false; + } + + virtual bool OnPointsProcess(Object *const in, Object *const out) { + UNUSED(in) + UNUSED(out) + return false; + } + + virtual bool OnDepthProcess(Object *const in, Object *const out) { + UNUSED(in) + UNUSED(out) + return false; + } + + protected: + API *api_; +}; + +inline Plugin::~Plugin() = default; + +using plugin_version_code_t = std::uint32_t(); +using plugin_create_t = Plugin *(); +using plugin_destroy_t = void(Plugin *); + +MYNTEYE_END_NAMESPACE + +extern "C" { + +MYNTEYE_API std::uint32_t plugin_version_code(); + +MYNTEYE_API mynteye::Plugin *plugin_create(); + +MYNTEYE_API void plugin_destroy(mynteye::Plugin *plugin); +} + +#endif // MYNTEYE_PLUGIN_H_ NOLINT diff --git a/src/api/processor/object.h b/src/api/processor/object.h index 51faf7b..e44d68a 100644 --- a/src/api/processor/object.h +++ b/src/api/processor/object.h @@ -11,7 +11,7 @@ MYNTEYE_BEGIN_NAMESPACE /** * Input & output object. */ -struct Object { +struct MYNTEYE_API Object { Object() = default; virtual ~Object() = default; @@ -28,7 +28,7 @@ struct Object { } }; -struct ObjMat : public Object { +struct MYNTEYE_API ObjMat : public Object { ObjMat() = default; explicit ObjMat(const cv::Mat &value) : value(value) {} @@ -41,7 +41,7 @@ struct ObjMat : public Object { } }; -struct ObjMat2 : public Object { +struct MYNTEYE_API ObjMat2 : public Object { ObjMat2() = default; ObjMat2(const cv::Mat &first, const cv::Mat &second) : first(first), second(second) {} diff --git a/src/api/synthetic.cc b/src/api/synthetic.cc index f48e4f1..3263a4e 100644 --- a/src/api/synthetic.cc +++ b/src/api/synthetic.cc @@ -6,6 +6,7 @@ #include #include +#include "api/plugin.h" #include "api/processor/depth_processor.h" #include "api/processor/disparity_normalized_processor.h" #include "api/processor/disparity_processor.h" @@ -31,7 +32,7 @@ api::StreamData data2api(const device::StreamData &data) { } // namespace -Synthetic::Synthetic(API *api) : api_(api) { +Synthetic::Synthetic(API *api) : api_(api), plugin_(nullptr) { VLOG(2) << __func__; CHECK_NOTNULL(api_); InitStreamSupports(); @@ -209,6 +210,10 @@ std::vector Synthetic::GetStreamDatas(const Stream &stream) { return {}; } +void Synthetic::SetPlugin(std::shared_ptr plugin) { + plugin_ = plugin; +} + void Synthetic::InitStreamSupports() { auto &&device = api_->device(); if (device->Supports(Stream::LEFT) && device->Supports(Stream::RIGHT)) { @@ -466,42 +471,47 @@ void Synthetic::ProcessNativeStream( bool Synthetic::OnRectifyProcess( Object *const in, Object *const out, Processor *const parent) { - UNUSED(in) - UNUSED(out) UNUSED(parent) + if (plugin_ && plugin_->OnRectifyProcess(in, out)) { + return true; + } return GetStreamEnabledMode(Stream::LEFT_RECTIFIED) != MODE_SYNTHETIC; // && GetStreamEnabledMode(Stream::RIGHT_RECTIFIED) != MODE_SYNTHETIC } bool Synthetic::OnDisparityProcess( Object *const in, Object *const out, Processor *const parent) { - UNUSED(in) - UNUSED(out) UNUSED(parent) + if (plugin_ && plugin_->OnDisparityProcess(in, out)) { + return true; + } return GetStreamEnabledMode(Stream::DISPARITY) != MODE_SYNTHETIC; } bool Synthetic::OnDisparityNormalizedProcess( Object *const in, Object *const out, Processor *const parent) { - UNUSED(in) - UNUSED(out) UNUSED(parent) + if (plugin_ && plugin_->OnDisparityNormalizedProcess(in, out)) { + return true; + } return GetStreamEnabledMode(Stream::DISPARITY_NORMALIZED) != MODE_SYNTHETIC; } bool Synthetic::OnPointsProcess( Object *const in, Object *const out, Processor *const parent) { - UNUSED(in) - UNUSED(out) UNUSED(parent) + if (plugin_ && plugin_->OnPointsProcess(in, out)) { + return true; + } return GetStreamEnabledMode(Stream::POINTS) != MODE_SYNTHETIC; } bool Synthetic::OnDepthProcess( Object *const in, Object *const out, Processor *const parent) { - UNUSED(in) - UNUSED(out) UNUSED(parent) + if (plugin_ && plugin_->OnDepthProcess(in, out)) { + return true; + } return GetStreamEnabledMode(Stream::DEPTH) != MODE_SYNTHETIC; } diff --git a/src/api/synthetic.h b/src/api/synthetic.h index bf5af53..92ca28d 100644 --- a/src/api/synthetic.h +++ b/src/api/synthetic.h @@ -13,6 +13,7 @@ MYNTEYE_BEGIN_NAMESPACE class API; class Object; +class Plugin; class Processor; class Synthetic { @@ -46,6 +47,8 @@ class Synthetic { api::StreamData GetStreamData(const Stream &stream); std::vector GetStreamDatas(const Stream &stream); + void SetPlugin(std::shared_ptr plugin); + private: void InitStreamSupports(); @@ -90,6 +93,8 @@ class Synthetic { std::map stream_callbacks_; std::shared_ptr processor_; + + std::shared_ptr plugin_; }; template diff --git a/src/internal/dl.cc b/src/internal/dl.cc new file mode 100644 index 0000000..1447f51 --- /dev/null +++ b/src/internal/dl.cc @@ -0,0 +1,114 @@ +#include "internal/dl.h" + +#include + +MYNTEYE_BEGIN_NAMESPACE + +#if defined(OS_WIN) && !defined(OS_MINGW) && !defined(OS_CYGWIN) + +namespace { + +// How to get the error message from the error code returned by GetLastError()? +// https://stackoverflow.com/questions/9272415/how-to-convert-dword-to-char +std::string GetLastErrorAsString() { + DWORD dw = ::GetLastError(); + if (dw == 0) + return std::string(); + LPSTR lpMsgBuf; + size_t size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, + NULL); + std::string message(lpMsgBuf, size); + LocalFree(lpMsgBuf); + return message; +} + +} // namespace + +#endif + +DL::DL() : handle(nullptr) { + VLOG(2) << __func__; +} + +DL::DL(const char *filename) : handle(nullptr) { + VLOG(2) << __func__; + Open(filename); +} + +DL::~DL() { + VLOG(2) << __func__; + Close(); +} + +bool DL::Open(const char *filename) { + if (handle != nullptr) { + VLOG(2) << "Already opened, do nothing"; + // Close(); + return false; + } +#if defined(OS_WIN) && !defined(OS_MINGW) && !defined(OS_CYGWIN) + handle = LoadLibraryEx(filename, nullptr, 0); +#else + handle = dlopen(filename, RTLD_LAZY); +#endif + if (handle == nullptr) { + VLOG(2) << "Open library failed: " << filename; + return false; + } else { + return true; + } +} + +bool DL::IsOpened() { + return handle != nullptr; +} + +void *DL::Sym(const char *symbol) { + if (handle == nullptr) { + VLOG(2) << "Not opened, do nothing"; + return nullptr; + } +#if defined(OS_WIN) && !defined(OS_MINGW) && !defined(OS_CYGWIN) + void *f = GetProcAddress(handle, symbol); + if (f == nullptr) { + VLOG(2) << "Load symbol failed: " << symbol; + } +#else + dlerror(); // reset errors + void *f = dlsym(handle, symbol); + const char *error = dlerror(); + if (error != nullptr) { + VLOG(2) << "Load symbol failed: " << symbol; + f = nullptr; + } +#endif + return f; +} + +int DL::Close() { + int ret = 0; + if (handle == nullptr) { + VLOG(2) << "Not opened, do nothing"; + } else { +#if defined(OS_WIN) && !defined(OS_MINGW) && !defined(OS_CYGWIN) + ret = FreeLibrary(handle) ? 0 : 1; +#else + ret = dlclose(handle); +#endif + handle = nullptr; + } + return ret; +} + +const char *DL::Error() { +#if defined(OS_WIN) && !defined(OS_MINGW) && !defined(OS_CYGWIN) + return GetLastErrorAsString().c_str(); +#else + return dlerror(); +#endif +} + +MYNTEYE_END_NAMESPACE diff --git a/src/internal/dl.h b/src/internal/dl.h new file mode 100644 index 0000000..29d487f --- /dev/null +++ b/src/internal/dl.h @@ -0,0 +1,56 @@ +#ifndef MYNTEYE_INTERNAL_DL_H_ // NOLINT +#define MYNTEYE_INTERNAL_DL_H_ +#pragma once + +#include "mynteye/mynteye.h" + +#if defined(OS_WIN) && !defined(OS_MINGW) && !defined(OS_CYGWIN) +#include +#else +#include +#endif + +MYNTEYE_BEGIN_NAMESPACE + +#if defined(OS_WIN) && !defined(OS_MINGW) && !defined(OS_CYGWIN) +using DLLIB = HMODULE; +#else +using DLLIB = void *; +#endif + +// Dynamic loading +// https://en.wikipedia.org/wiki/Dynamic_loading +// C++ dlopen mini HOWTO +// http://tldp.org/HOWTO/C++-dlopen/ +class MYNTEYE_API DL { + public: + DL(); + explicit DL(const char *filename); + ~DL(); + + bool Open(const char *filename); + + bool IsOpened(); + + void *Sym(const char *symbol); + + template + Func *Sym(const char *symbol); + + int Close(); + + const char *Error(); + + private: + DLLIB handle; +}; + +template +Func *DL::Sym(const char *symbol) { + void *f = Sym(symbol); + return reinterpret_cast(f); +} + +MYNTEYE_END_NAMESPACE + +#endif // MYNTEYE_INTERNAL_DL_H_ NOLINT