videoio: add routines to query information about backends API
authorAlexander Alekhin <alexander.alekhin@intel.com>
Thu, 19 Jul 2018 13:14:50 +0000 (16:14 +0300)
committerAlexander Alekhin <alexander.alekhin@intel.com>
Thu, 19 Jul 2018 14:27:37 +0000 (17:27 +0300)
into cv::videoio_registry namespace

modules/python/src2/cv2.cpp
modules/python/test/test_videoio.py [new file with mode: 0644]
modules/videoio/include/opencv2/videoio.hpp
modules/videoio/include/opencv2/videoio/registry.hpp [new file with mode: 0644]
modules/videoio/misc/python/pyopencv_videoio.hpp [new file with mode: 0644]
modules/videoio/src/videoio_registry.cpp
modules/videoio/test/test_precomp.hpp
modules/videoio/test/test_video_io.cpp

index 179bf67..03fd912 100644 (file)
@@ -1563,8 +1563,6 @@ PyObject* pyopencv_from(const Moments& m)
                          "nu30", m.nu30, "nu21", m.nu21, "nu12", m.nu12, "nu03", m.nu03);
 }
 
-#include "pyopencv_custom_headers.h"
-
 static int OnError(int status, const char *func_name, const char *err_msg, const char *file_name, int line, void *userdata)
 {
     PyGILState_STATE gstate;
@@ -1802,6 +1800,7 @@ static int convert_to_char(PyObject *o, char *dst, const char *name = "no_name")
 #  pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 #endif
 
+#include "pyopencv_custom_headers.h"
 #include "pyopencv_generated_types.h"
 #include "pyopencv_generated_funcs.h"
 
diff --git a/modules/python/test/test_videoio.py b/modules/python/test/test_videoio.py
new file mode 100644 (file)
index 0000000..2bbfeec
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+from __future__ import print_function
+
+import numpy as np
+import cv2 as cv
+
+from tests_common import NewOpenCVTests
+
+class Bindings(NewOpenCVTests):
+
+    def check_name(self, name):
+        #print(name)
+        self.assertFalse(name == None)
+        self.assertFalse(name == "")
+
+    def test_registry(self):
+        self.check_name(cv.videoio_registry.getBackendName(cv.CAP_ANY));
+        self.check_name(cv.videoio_registry.getBackendName(cv.CAP_FFMPEG))
+        self.check_name(cv.videoio_registry.getBackendName(cv.CAP_OPENCV_MJPEG))
+        backends = cv.videoio_registry.getBackends()
+        for backend in backends:
+            self.check_name(cv.videoio_registry.getBackendName(backend))
+
+if __name__ == '__main__':
+    NewOpenCVTests.bootstrap()
index d43e703..eef840b 100644 (file)
@@ -59,6 +59,7 @@
     @defgroup videoio_c C API for video I/O
     @defgroup videoio_ios iOS glue for video I/O
     @defgroup videoio_winrt WinRT glue for video I/O
+    @defgroup videoio_registry Query I/O API backends registry
   @}
 */
 
diff --git a/modules/videoio/include/opencv2/videoio/registry.hpp b/modules/videoio/include/opencv2/videoio/registry.hpp
new file mode 100644 (file)
index 0000000..7404c68
--- /dev/null
@@ -0,0 +1,44 @@
+// 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.
+
+#ifndef OPENCV_VIDEOIO_REGISTRY_HPP
+#define OPENCV_VIDEOIO_REGISTRY_HPP
+
+#include <opencv2/videoio.hpp>
+
+namespace cv { namespace videoio_registry {
+/** @addtogroup videoio_registry
+This section contains API description how to query/configure available Video I/O backends.
+
+Runtime configuration options:
+- enable debug mode: `OPENCV_VIDEOIO_DEBUG=1`
+- change backend priority: `OPENCV_VIDEOIO_PRIORITY_<backend>=9999`
+- disable backend: `OPENCV_VIDEOIO_PRIORITY_<backend>=0`
+- specify list of backends with high priority (>100000): `OPENCV_VIDEOIO_PRIORITY_LIST=FFMPEG,GSTREAMER`
+
+@{
+ */
+
+
+/** @brief Returns backend API name or "unknown"
+@param api backend ID (#VideoCaptureAPIs)
+*/
+CV_EXPORTS_W cv::String getBackendName(VideoCaptureAPIs api);
+
+/** @brief Returns list of all builtin backends */
+CV_EXPORTS_W std::vector<VideoCaptureAPIs> getBackends();
+
+/** @brief Returns list of available backends which works via `cv::VideoCapture(int index)` */
+CV_EXPORTS_W std::vector<VideoCaptureAPIs> getCameraBackends();
+
+/** @brief Returns list of available backends which works via `cv::VideoCapture(filename)` */
+CV_EXPORTS_W std::vector<VideoCaptureAPIs> getStreamBackends();
+
+/** @brief Returns list of available backends which works via `cv::VideoWriter()` */
+CV_EXPORTS_W std::vector<VideoCaptureAPIs> getWriterBackends();
+
+//! @}
+}} // namespace
+
+#endif // OPENCV_VIDEOIO_REGISTRY_HPP
diff --git a/modules/videoio/misc/python/pyopencv_videoio.hpp b/modules/videoio/misc/python/pyopencv_videoio.hpp
new file mode 100644 (file)
index 0000000..453a57a
--- /dev/null
@@ -0,0 +1,50 @@
+#ifdef HAVE_OPENCV_VIDEOIO
+typedef std::vector<VideoCaptureAPIs> vector_VideoCaptureAPIs;
+
+template<>
+bool pyopencv_to(PyObject *o, cv::VideoCaptureAPIs &v, const char *name)
+{
+    (void)name;
+    v = CAP_ANY;
+    if (!o || o == Py_None)
+        return false;
+    else if (PyLong_Check(o))
+    {
+        v = VideoCaptureAPIs((int64)PyLong_AsLongLong(o));
+        return true;
+    }
+    else if (PyInt_Check(o))
+    {
+        v = VideoCaptureAPIs((int64)PyInt_AS_LONG(o));
+        return true;
+    }
+    else
+        return false;
+}
+
+template<>
+PyObject* pyopencv_from(const cv::VideoCaptureAPIs &v)
+{
+    return pyopencv_from((int)(v));
+}
+
+template<> struct pyopencvVecConverter<cv::VideoCaptureAPIs>
+{
+    static bool to(PyObject* obj, std::vector<cv::VideoCaptureAPIs>& value, const ArgInfo info)
+    {
+        return pyopencv_to_generic_vec(obj, value, info);
+    }
+
+    static PyObject* from(const std::vector<cv::VideoCaptureAPIs>& value)
+    {
+        return pyopencv_from_generic_vec(value);
+    }
+};
+
+template<>
+bool pyopencv_to(PyObject *o, std::vector<cv::VideoCaptureAPIs>& apis, const char *name)
+{
+  return pyopencvVecConverter<cv::VideoCaptureAPIs>::to(o, apis, ArgInfo(name, false));
+}
+
+#endif // HAVE_OPENCV_VIDEOIO
index 9f0abc5..85fc239 100644 (file)
@@ -6,6 +6,8 @@
 
 #include "videoio_registry.hpp"
 
+#include "opencv2/videoio/registry.hpp"
+
 #include "cap_intelperc.hpp"
 #include "cap_dshow.hpp"
 
@@ -247,6 +249,8 @@ public:
         return g_instance;
     }
 
+    inline std::vector<VideoBackendInfo> getEnabledBackends() const { return enabledBackends; }
+
     inline std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex() const
     {
         std::vector<VideoBackendInfo> result;
@@ -302,6 +306,58 @@ std::vector<VideoBackendInfo> getAvailableBackends_Writer()
     return result;
 }
 
+cv::String getBackendName(VideoCaptureAPIs api)
+{
+    if (api == CAP_ANY)
+        return "CAP_ANY";  // special case, not a part of backends list
+    const int N = sizeof(builtin_backends)/sizeof(builtin_backends[0]);
+    for (size_t i = 0; i < N; i++)
+    {
+        const VideoBackendInfo& backend = builtin_backends[i];
+        if (backend.id == api)
+            return backend.name;
+    }
+    return cv::format("UnknownVideoAPI(%d)", (int)api);
+}
+
+std::vector<VideoCaptureAPIs> getBackends()
+{
+    std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getEnabledBackends();
+    std::vector<VideoCaptureAPIs> result;
+    for (size_t i = 0; i < backends.size(); i++)
+        result.push_back((VideoCaptureAPIs)backends[i].id);
+    return result;
+}
+
+std::vector<VideoCaptureAPIs> getCameraBackends()
+{
+    const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex();
+    std::vector<VideoCaptureAPIs> result;
+    for (size_t i = 0; i < backends.size(); i++)
+        result.push_back((VideoCaptureAPIs)backends[i].id);
+    return result;
+
+}
+
+std::vector<VideoCaptureAPIs> getStreamBackends()
+{
+    const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename();
+    std::vector<VideoCaptureAPIs> result;
+    for (size_t i = 0; i < backends.size(); i++)
+        result.push_back((VideoCaptureAPIs)backends[i].id);
+    return result;
+
+}
+
+std::vector<VideoCaptureAPIs> getWriterBackends()
+{
+    const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_Writer();
+    std::vector<VideoCaptureAPIs> result;
+    for (size_t i = 0; i < backends.size(); i++)
+        result.push_back((VideoCaptureAPIs)backends[i].id);
+    return result;
+}
+
 } // namespace registry
 
 #define TRY_OPEN(backend_func) \
index 8d9f5e0..e3612ad 100644 (file)
@@ -6,10 +6,26 @@
 
 #include "opencv2/ts.hpp"
 #include "opencv2/videoio.hpp"
+#include "opencv2/videoio/registry.hpp"
 #include "opencv2/imgproc/imgproc_c.h"
 
 #include "opencv2/core/private.hpp"
 
+namespace cv {
+
+inline std::ostream &operator<<(std::ostream &out, const VideoCaptureAPIs& api)
+{
+    out << cv::videoio_registry::getBackendName(api); return out;
+}
+
+static inline void PrintTo(const cv::VideoCaptureAPIs& api, std::ostream* os)
+{
+    *os << cv::videoio_registry::getBackendName(api);
+}
+
+} // namespace
+
+
 inline std::string fourccToString(int fourcc)
 {
     return cv::format("%c%c%c%c", fourcc & 255, (fourcc >> 8) & 255, (fourcc >> 16) & 255, (fourcc >> 24) & 255);
@@ -55,4 +71,15 @@ public:
     }
 };
 
+
+static inline bool isBackendAvailable(cv::VideoCaptureAPIs api, const std::vector<cv::VideoCaptureAPIs>& api_list)
+{
+    for (size_t i = 0; i < api_list.size(); i++)
+    {
+        if (api_list[i] == api)
+            return true;
+    }
+    return false;
+}
+
 #endif
index c1834be..7dcdc1d 100644 (file)
 namespace opencv_test
 {
 
-struct VideoCaptureAPI
-{
-    VideoCaptureAPIs api;
-
-    inline const char * toString() const
-    {
-        switch (api)
-        {
-        case CAP_ANY: return "CAP_ANY";
-    #ifdef __linux__
-        case CAP_V4L2: return "CAP_V4L/CAP_V4L2";
-    #else
-        case CAP_VFW: return "CAP_VFW";
-    #endif
-        case CAP_FIREWIRE: return "CAP_FIREWIRE";
-        case CAP_QT: return "CAP_QT";
-        case CAP_UNICAP: return "CAP_UNICAP";
-        case CAP_DSHOW: return "CAP_DSHOW";
-        case CAP_PVAPI: return "CAP_PVAPI";
-        case CAP_OPENNI: return "CAP_OPENNI";
-        case CAP_OPENNI_ASUS: return "CAP_OPENNI_ASUS";
-        case CAP_ANDROID: return "CAP_ANDROID";
-        case CAP_XIAPI: return "CAP_XIAPI";
-        case CAP_AVFOUNDATION: return "CAP_AVFOUNDATION";
-        case CAP_GIGANETIX: return "CAP_GIGANETIX";
-        case CAP_MSMF: return "CAP_MSMF";
-        case CAP_WINRT: return "CAP_WINRT";
-        case CAP_INTELPERC: return "CAP_INTELPERC";
-        case CAP_OPENNI2: return "CAP_OPENNI2";
-        case CAP_OPENNI2_ASUS: return "CAP_OPENNI2_ASUS";
-        case CAP_GPHOTO2: return "CAP_GPHOTO2";
-        case CAP_GSTREAMER: return "CAP_GSTREAMER";
-        case CAP_FFMPEG: return "CAP_FFMPEG";
-        case CAP_IMAGES: return "CAP_IMAGES";
-        case CAP_ARAVIS: return "CAP_ARAVIS";
-        case CAP_OPENCV_MJPEG: return "CAP_OPENCV_MJPEG";
-        case CAP_INTEL_MFX: return "CAP_INTEL_MFX";
-        case CAP_XINE: return "CAP_XINE";
-        }
-        return "unknown";
-    }
-    VideoCaptureAPI(int api_ = CAP_ANY) : api((VideoCaptureAPIs)api_) {}
-    operator int() { return api; }
-};
-
-inline std::ostream &operator<<(std::ostream &out, const VideoCaptureAPI & api)
-{
-    out << api.toString(); return out;
-}
-
 class Videoio_Test_Base
 {
 protected:
     string ext;
     string video_file;
-    VideoCaptureAPI apiPref;
+    VideoCaptureAPIs apiPref;
 protected:
     Videoio_Test_Base() {}
     virtual ~Videoio_Test_Base() {}
@@ -131,6 +81,8 @@ protected:
 public:
     void doTest()
     {
+        if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))
+            throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
         VideoCapture cap;
         ASSERT_NO_THROW(cap.open(video_file, apiPref));
         if (!cap.isOpened())
@@ -200,7 +152,7 @@ public:
 };
 
 //==================================================================================================
-typedef tuple<string, VideoCaptureAPI> Backend_Type_Params;
+typedef tuple<string, VideoCaptureAPIs> Backend_Type_Params;
 
 class Videoio_Bunny : public Videoio_Test_Base, public testing::TestWithParam<Backend_Type_Params>
 {
@@ -214,6 +166,8 @@ public:
     }
     void doFrameCountTest()
     {
+        if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))
+            throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
         VideoCapture cap;
         EXPECT_NO_THROW(cap.open(video_file, apiPref));
         if (!cap.isOpened())
@@ -274,7 +228,7 @@ struct Ext_Fourcc_PSNR
     string ext;
     string fourcc;
     float PSNR;
-    VideoCaptureAPI api;
+    VideoCaptureAPIs api;
 };
 typedef tuple<Size, Ext_Fourcc_PSNR> Size_Ext_Fourcc_PSNR;
 
@@ -348,7 +302,7 @@ public:
 
 //==================================================================================================
 
-static VideoCaptureAPI backend_params[] = {
+static const VideoCaptureAPIs backend_params[] = {
 #ifdef HAVE_QUICKTIME
     CAP_QT,
 #endif
@@ -383,7 +337,7 @@ static VideoCaptureAPI backend_params[] = {
     // CAP_INTEL_MFX
 };
 
-static string bunny_params[] = {
+static const string bunny_params[] = {
 #ifdef HAVE_VIDEO_INPUT
     string("wmv"),
     string("mov"),