From 896bffb543d1c80781f5f217caffdedc98a8d8f1 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 19 Apr 2021 01:39:59 +0000 Subject: [PATCH] videoio(plugin): add query API for plugins --- .../include/opencv2/videoio/registry.hpp | 27 ++++- modules/videoio/src/backend.hpp | 12 ++ modules/videoio/src/backend_plugin.cpp | 92 ++++++++++++++- modules/videoio/src/backend_static.cpp | 4 + modules/videoio/src/videoio_registry.cpp | 75 +++++++++++++ modules/videoio/test/test_plugins.cpp | 105 ++++++++++++++++++ 6 files changed, 310 insertions(+), 5 deletions(-) create mode 100644 modules/videoio/test/test_plugins.cpp diff --git a/modules/videoio/include/opencv2/videoio/registry.hpp b/modules/videoio/include/opencv2/videoio/registry.hpp index 89fb5a836c..cf72247b3f 100644 --- a/modules/videoio/include/opencv2/videoio/registry.hpp +++ b/modules/videoio/include/opencv2/videoio/registry.hpp @@ -39,7 +39,32 @@ CV_EXPORTS_W std::vector getStreamBackends(); CV_EXPORTS_W std::vector getWriterBackends(); /** @brief Returns true if backend is available */ -CV_EXPORTS bool hasBackend(VideoCaptureAPIs api); +CV_EXPORTS_W bool hasBackend(VideoCaptureAPIs api); + +/** @brief Returns true if backend is built in (false if backend is used as plugin) */ +CV_EXPORTS_W bool isBackendBuiltIn(VideoCaptureAPIs api); + +/** @brief Returns description and ABI/API version of videoio plugin's camera interface */ +CV_EXPORTS_W std::string getCameraBackendPluginVersion( + VideoCaptureAPIs api, + CV_OUT int& version_ABI, + CV_OUT int& version_API +); + +/** @brief Returns description and ABI/API version of videoio plugin's stream capture interface */ +CV_EXPORTS_W std::string getStreamBackendPluginVersion( + VideoCaptureAPIs api, + CV_OUT int& version_ABI, + CV_OUT int& version_API +); + +/** @brief Returns description and ABI/API version of videoio plugin's writer interface */ +CV_EXPORTS_W std::string getWriterBackendPluginVersion( + VideoCaptureAPIs api, + CV_OUT int& version_ABI, + CV_OUT int& version_API +); + //! @} }} // namespace diff --git a/modules/videoio/src/backend.hpp b/modules/videoio/src/backend.hpp index ecf0e0d1d3..2a95ec05aa 100644 --- a/modules/videoio/src/backend.hpp +++ b/modules/videoio/src/backend.hpp @@ -27,6 +27,7 @@ class IBackendFactory public: virtual ~IBackendFactory() {} virtual Ptr getBackend() const = 0; + virtual bool isBuiltIn() const = 0; }; //============================================================================= @@ -48,6 +49,17 @@ Ptr createPluginBackendFactory(VideoCaptureAPIs id, const char* void applyParametersFallback(const Ptr& cap, const VideoCaptureParameters& params); +std::string getCapturePluginVersion( + const Ptr& backend_factory, + CV_OUT int& version_ABI, + CV_OUT int& version_API +); +std::string getWriterPluginVersion( + const Ptr& backend_factory, + CV_OUT int& version_ABI, + CV_OUT int& version_API +); + } // namespace cv:: #endif // BACKEND_HPP_DEFINED diff --git a/modules/videoio/src/backend_plugin.cpp b/modules/videoio/src/backend_plugin.cpp index ad34602ee2..9602032556 100644 --- a/modules/videoio/src/backend_plugin.cpp +++ b/modules/videoio/src/backend_plugin.cpp @@ -210,6 +210,24 @@ public: Ptr createCapture(const std::string &filename, const VideoCaptureParameters& params) const CV_OVERRIDE; Ptr createWriter(const std::string& filename, int fourcc, double fps, const cv::Size& sz, const VideoWriterParameters& params) const CV_OVERRIDE; + + std::string getCapturePluginVersion(CV_OUT int& version_ABI, CV_OUT int& version_API) + { + CV_Assert(capture_api_ || plugin_api_); + const OpenCV_API_Header& api_header = capture_api_ ? capture_api_->api_header : plugin_api_->api_header; + version_ABI = api_header.min_api_version; + version_API = api_header.api_version; + return api_header.api_description; + } + + std::string getWriterPluginVersion(CV_OUT int& version_ABI, CV_OUT int& version_API) + { + CV_Assert(writer_api_ || plugin_api_); + const OpenCV_API_Header& api_header = writer_api_ ? writer_api_->api_header : plugin_api_->api_header; + version_ABI = api_header.min_api_version; + version_API = api_header.api_version; + return api_header.api_description; + } }; class PluginBackendFactory : public IBackendFactory @@ -228,15 +246,42 @@ public: } Ptr getBackend() const CV_OVERRIDE + { + initBackend(); + return backend.staticCast(); + } + + bool isBuiltIn() const CV_OVERRIDE { return false; } + + std::string getCapturePluginVersion( + CV_OUT int& version_ABI, + CV_OUT int& version_API) const + { + initBackend(); + if (!backend) + CV_Error_(Error::StsNotImplemented, ("Backend '%s' is not available", baseName_)); + return backend->getCapturePluginVersion(version_ABI, version_API); + } + + std::string getWriterPluginVersion( + CV_OUT int& version_ABI, + CV_OUT int& version_API) const + { + initBackend(); + if (!backend) + CV_Error_(Error::StsNotImplemented, ("Backend '%s' is not available", baseName_)); + return backend->getWriterPluginVersion(version_ABI, version_API); + } + +protected: + inline void initBackend() const { if (!initialized) { - const_cast(this)->initBackend(); + const_cast(this)->initBackend_(); } - return backend.staticCast(); } -protected: - void initBackend() + void initBackend_() { AutoLock lock(getInitializationMutex()); try { @@ -688,4 +733,43 @@ Ptr createPluginBackendFactory(VideoCaptureAPIs id, const char* #endif } + +std::string getCapturePluginVersion( + const Ptr& backend_factory, + CV_OUT int& version_ABI, + CV_OUT int& version_API +) +{ +#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS) + using namespace impl; + CV_Assert(backend_factory); + PluginBackendFactory* plugin_backend_factory = dynamic_cast(backend_factory.get()); + CV_Assert(plugin_backend_factory); + return plugin_backend_factory->getCapturePluginVersion(version_ABI, version_API); +#else + CV_UNUSED(version_ABI); + CV_UNUSED(version_API); + CV_Error(Error::StsBadFunc, "Plugins are not available in this build"); +#endif +} + +std::string getWriterPluginVersion( + const Ptr& backend_factory, + CV_OUT int& version_ABI, + CV_OUT int& version_API +) +{ +#if OPENCV_HAVE_FILESYSTEM_SUPPORT && defined(ENABLE_PLUGINS) + using namespace impl; + CV_Assert(backend_factory); + PluginBackendFactory* plugin_backend_factory = dynamic_cast(backend_factory.get()); + CV_Assert(plugin_backend_factory); + return plugin_backend_factory->getWriterPluginVersion(version_ABI, version_API); +#else + CV_UNUSED(version_ABI); + CV_UNUSED(version_API); + CV_Error(Error::StsBadFunc, "Plugins are not available in this build"); +#endif +} + } // namespace diff --git a/modules/videoio/src/backend_static.cpp b/modules/videoio/src/backend_static.cpp index 2e0088f558..3001906acf 100644 --- a/modules/videoio/src/backend_static.cpp +++ b/modules/videoio/src/backend_static.cpp @@ -99,6 +99,8 @@ public: { return backend.staticCast(); } + + bool isBuiltIn() const CV_OVERRIDE { return true; } }; @@ -165,6 +167,8 @@ public: { return backend.staticCast(); } + + bool isBuiltIn() const CV_OVERRIDE { return true; } }; diff --git a/modules/videoio/src/videoio_registry.cpp b/modules/videoio/src/videoio_registry.cpp index 59d96d162c..d15145ba6c 100644 --- a/modules/videoio/src/videoio_registry.cpp +++ b/modules/videoio/src/videoio_registry.cpp @@ -403,6 +403,81 @@ bool hasBackend(VideoCaptureAPIs api) return false; } +bool isBackendBuiltIn(VideoCaptureAPIs api) +{ + std::vector backends = VideoBackendRegistry::getInstance().getEnabledBackends(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + if (api == info.id) + { + CV_Assert(!info.backendFactory.empty()); + return info.backendFactory->isBuiltIn(); + } + } + return false; +} + +std::string getCameraBackendPluginVersion(VideoCaptureAPIs api, + CV_OUT int& version_ABI, + CV_OUT int& version_API +) +{ + const std::vector backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + if (api == info.id) + { + CV_Assert(!info.backendFactory.empty()); + CV_Assert(!info.backendFactory->isBuiltIn()); + return getCapturePluginVersion(info.backendFactory, version_ABI, version_API); + } + } + CV_Error(Error::StsError, "Unknown or wrong backend ID"); +} + +std::string getStreamBackendPluginVersion(VideoCaptureAPIs api, + CV_OUT int& version_ABI, + CV_OUT int& version_API +) +{ + const std::vector backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + if (api == info.id) + { + CV_Assert(!info.backendFactory.empty()); + CV_Assert(!info.backendFactory->isBuiltIn()); + return getCapturePluginVersion(info.backendFactory, version_ABI, version_API); + } + } + CV_Error(Error::StsError, "Unknown or wrong backend ID"); +} + + +/** @brief Returns description and ABI/API version of videoio plugin's writer interface */ +std::string getWriterBackendPluginVersion(VideoCaptureAPIs api, + CV_OUT int& version_ABI, + CV_OUT int& version_API +) +{ + const std::vector backends = VideoBackendRegistry::getInstance().getAvailableBackends_Writer(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + if (api == info.id) + { + CV_Assert(!info.backendFactory.empty()); + CV_Assert(!info.backendFactory->isBuiltIn()); + return getWriterPluginVersion(info.backendFactory, version_ABI, version_API); + } + } + CV_Error(Error::StsError, "Unknown or wrong backend ID"); +} + + } // namespace registry } // namespace diff --git a/modules/videoio/test/test_plugins.cpp b/modules/videoio/test/test_plugins.cpp new file mode 100644 index 0000000000..3bae600be1 --- /dev/null +++ b/modules/videoio/test/test_plugins.cpp @@ -0,0 +1,105 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "test_precomp.hpp" + +namespace opencv_test { namespace { + +enum VideoBackendMode +{ + MODE_CAMERA, + MODE_STREAM, + MODE_WRITER, +}; + +static +void dumpBackendInfo(VideoCaptureAPIs backend, enum VideoBackendMode mode) +{ + std::string name; + try + { + name = videoio_registry::getBackendName(backend); + } + catch (const std::exception& e) + { + ADD_FAILURE() << "Can't query name of backend=" << backend << ": " << e.what(); + } + catch (...) + { + ADD_FAILURE() << "Can't query name of backend=" << backend << ": unknown C++ exception"; + } + bool isBuiltIn = true; + try + { + isBuiltIn = videoio_registry::isBackendBuiltIn(backend); + } + catch (const std::exception& e) + { + ADD_FAILURE() << "Failed isBackendBuiltIn(backend=" << backend << "): " << e.what(); + cout << name << " - UNKNOWN TYPE" << endl; + return; + } + if (isBuiltIn) + { + cout << name << " - BUILTIN" << endl; + return; + } + + std::string description = "NO_DESCRIPTION"; + int version_ABI = 0; + int version_API = 0; + try + { + if (mode == MODE_CAMERA) + description = videoio_registry::getCameraBackendPluginVersion(backend, version_ABI, version_API); + else if (mode == MODE_STREAM) + description = videoio_registry::getStreamBackendPluginVersion(backend, version_ABI, version_API); + else if (mode == MODE_WRITER) + description = videoio_registry::getWriterBackendPluginVersion(backend, version_ABI, version_API); + else + CV_Error(Error::StsInternal, ""); + cout << name << " - PLUGIN (" << description << ") ABI=" << version_ABI << " API=" << version_API << endl; + return; + } + catch (const cv::Exception& e) + { + if (e.code == Error::StsNotImplemented) + { + cout << name << " - PLUGIN - NOT LOADED" << endl; + return; + } + ADD_FAILURE() << "Failed getBackendPluginDescription(backend=" << backend << "): " << e.what(); + } + catch (const std::exception& e) + { + ADD_FAILURE() << "Failed getBackendPluginDescription(backend=" << backend << "): " << e.what(); + } + cout << name << " - PLUGIN (ERROR on quering information)" << endl; +} + +TEST(VideoIO_Plugins, query) +{ + const std::vector camera_backends = cv::videoio_registry::getCameraBackends(); + cout << "== Camera APIs (" << camera_backends.size() << "):" << endl; + for (auto backend : camera_backends) + { + dumpBackendInfo(backend, MODE_CAMERA); + } + + const std::vector stream_backends = cv::videoio_registry::getStreamBackends(); + cout << "== Stream capture APIs (" << stream_backends.size() << "):" << endl; + for (auto backend : stream_backends) + { + dumpBackendInfo(backend, MODE_STREAM); + } + + const std::vector writer_backends = cv::videoio_registry::getWriterBackends(); + cout << "== Writer APIs (" << writer_backends.size() << "):" << endl; + for (auto backend : writer_backends) + { + dumpBackendInfo(backend, MODE_WRITER); + } +} + +}}