videoio(plugin): add query API for plugins
authorAlexander Alekhin <alexander.a.alekhin@gmail.com>
Mon, 19 Apr 2021 01:39:59 +0000 (01:39 +0000)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Mon, 19 Apr 2021 14:25:45 +0000 (14:25 +0000)
modules/videoio/include/opencv2/videoio/registry.hpp
modules/videoio/src/backend.hpp
modules/videoio/src/backend_plugin.cpp
modules/videoio/src/backend_static.cpp
modules/videoio/src/videoio_registry.cpp
modules/videoio/test/test_plugins.cpp [new file with mode: 0644]

index 89fb5a836c99825f179f5a23d5fa2541523271d6..cf72247b3fa09c57518b84323adfd3214125217a 100644 (file)
@@ -39,7 +39,32 @@ CV_EXPORTS_W std::vector<VideoCaptureAPIs> getStreamBackends();
 CV_EXPORTS_W std::vector<VideoCaptureAPIs> 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
index ecf0e0d1d3f627a58e12bf9928012e38f84572b8..2a95ec05aa0e568f937a34d465cbb16da9cd29b2 100644 (file)
@@ -27,6 +27,7 @@ class IBackendFactory
 public:
     virtual ~IBackendFactory() {}
     virtual Ptr<IBackend> getBackend() const = 0;
+    virtual bool isBuiltIn() const = 0;
 };
 
 //=============================================================================
@@ -48,6 +49,17 @@ Ptr<IBackendFactory> createPluginBackendFactory(VideoCaptureAPIs id, const char*
 
 void applyParametersFallback(const Ptr<IVideoCapture>& cap, const VideoCaptureParameters& params);
 
+std::string getCapturePluginVersion(
+    const Ptr<IBackendFactory>& backend_factory,
+    CV_OUT int& version_ABI,
+    CV_OUT int& version_API
+);
+std::string getWriterPluginVersion(
+    const Ptr<IBackendFactory>& backend_factory,
+    CV_OUT int& version_ABI,
+    CV_OUT int& version_API
+);
+
 } // namespace cv::
 
 #endif // BACKEND_HPP_DEFINED
index ad34602ee2aa9cef643cc569e735671057800c4f..9602032556b883d928e0f8370899762ffa865eff 100644 (file)
@@ -210,6 +210,24 @@ public:
     Ptr<IVideoCapture> createCapture(const std::string &filename, const VideoCaptureParameters& params) const CV_OVERRIDE;
     Ptr<IVideoWriter> 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<IBackend> getBackend() const CV_OVERRIDE
+    {
+        initBackend();
+        return backend.staticCast<IBackend>();
+    }
+
+    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<PluginBackendFactory*>(this)->initBackend();
+            const_cast<PluginBackendFactory*>(this)->initBackend_();
         }
-        return backend.staticCast<IBackend>();
     }
-protected:
-    void initBackend()
+    void initBackend_()
     {
         AutoLock lock(getInitializationMutex());
         try {
@@ -688,4 +733,43 @@ Ptr<IBackendFactory> createPluginBackendFactory(VideoCaptureAPIs id, const char*
 #endif
 }
 
+
+std::string getCapturePluginVersion(
+    const Ptr<IBackendFactory>& 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<PluginBackendFactory*>(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<IBackendFactory>& 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<PluginBackendFactory*>(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
index 2e0088f558635bca94863e19dac55ee17d0fa9d3..3001906acfc4722b21d00a334d04a658714747d1 100644 (file)
@@ -99,6 +99,8 @@ public:
     {
         return backend.staticCast<IBackend>();
     }
+
+    bool isBuiltIn() const CV_OVERRIDE { return true; }
 };
 
 
@@ -165,6 +167,8 @@ public:
     {
         return backend.staticCast<IBackend>();
     }
+
+    bool isBuiltIn() const CV_OVERRIDE { return true; }
 };
 
 
index 59d96d162c2606a84533f9c5188a8ac702b996b0..d15145ba6c983676d2e22b47ca9b7bbfd69825a9 100644 (file)
@@ -403,6 +403,81 @@ bool hasBackend(VideoCaptureAPIs api)
     return false;
 }
 
+bool isBackendBuiltIn(VideoCaptureAPIs api)
+{
+    std::vector<VideoBackendInfo> 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<VideoBackendInfo> 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<VideoBackendInfo> 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<VideoBackendInfo> 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 (file)
index 0000000..3bae600
--- /dev/null
@@ -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<cv::VideoCaptureAPIs> 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<cv::VideoCaptureAPIs> 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<cv::VideoCaptureAPIs> writer_backends = cv::videoio_registry::getWriterBackends();
+    cout << "== Writer APIs (" << writer_backends.size() << "):" << endl;
+    for (auto backend : writer_backends)
+    {
+        dumpBackendInfo(backend, MODE_WRITER);
+    }
+}
+
+}}