1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 
5 #include "precomp.hpp"
6 
7 #include "videoio_registry.hpp"
8 
9 #include "opencv2/videoio/registry.hpp"
10 
11 #include "cap_librealsense.hpp"
12 #include "cap_dshow.hpp"
13 
14 #ifdef HAVE_MFX
15 #include "cap_mfx_reader.hpp"
16 #include "cap_mfx_writer.hpp"
17 #endif
18 
19 // All WinRT versions older than 8.0 should provide classes used for video support
20 #if defined(WINRT) && !defined(WINRT_8_0) && defined(__cplusplus_winrt)
21 #   include "cap_winrt_capture.hpp"
22 #   include "cap_winrt_bridge.hpp"
23 #   define WINRT_VIDEO
24 #endif
25 
26 #if defined _M_X64 && defined _MSC_VER && !defined CV_ICC
27 #pragma optimize("",off)
28 #pragma warning(disable: 4748)
29 #endif
30 
31 using namespace cv;
32 
33 namespace cv {
34 
35 namespace {
36 
37 #define DECLARE_DYNAMIC_BACKEND(cap, name, mode) \
38 { \
39     cap, (BackendMode)(mode), 1000, name, createPluginBackendFactory(cap, name) \
40 }
41 
42 #define DECLARE_STATIC_BACKEND(cap, name, mode, createCaptureFile, createCaptureCamera, createWriter) \
43 { \
44     cap, (BackendMode)(mode), 1000, name, createBackendFactory(createCaptureFile, createCaptureCamera, createWriter) \
45 }
46 
47 /** Ordering guidelines:
48 - modern optimized, multi-platform libraries: ffmpeg, gstreamer, Media SDK
49 - platform specific universal SDK: WINRT, AVFOUNDATION, MSMF/DSHOW, V4L/V4L2
50 - RGB-D: OpenNI/OpenNI2, REALSENSE
51 - special OpenCV (file-based): "images", "mjpeg"
52 - special camera SDKs, including stereo: other special SDKs: FIREWIRE/1394, XIMEA/ARAVIS/GIGANETIX/PVAPI(GigE)/uEye
53 - other: XINE, gphoto2, etc
54 */
55 static const struct VideoBackendInfo builtin_backends[] =
56 {
57 #ifdef HAVE_FFMPEG
58     DECLARE_STATIC_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, cvCreateFileCapture_FFMPEG_proxy, 0, cvCreateVideoWriter_FFMPEG_proxy),
59 #elif defined(ENABLE_PLUGINS) || defined(HAVE_FFMPEG_WRAPPER)
60     DECLARE_DYNAMIC_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
61 #endif
62 
63 #ifdef HAVE_GSTREAMER
64     DECLARE_STATIC_BACKEND(CAP_GSTREAMER, "GSTREAMER", MODE_CAPTURE_ALL | MODE_WRITER, createGStreamerCapture_file, createGStreamerCapture_cam, create_GStreamer_writer),
65 #elif defined(ENABLE_PLUGINS)
66     DECLARE_DYNAMIC_BACKEND(CAP_GSTREAMER, "GSTREAMER", MODE_CAPTURE_ALL | MODE_WRITER),
67 #endif
68 
69 #ifdef HAVE_MFX // Media SDK
70     DECLARE_STATIC_BACKEND(CAP_INTEL_MFX, "INTEL_MFX", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, create_MFX_capture, 0, create_MFX_writer),
71 #elif defined(ENABLE_PLUGINS)
72     DECLARE_DYNAMIC_BACKEND(CAP_INTEL_MFX, "INTEL_MFX", MODE_CAPTURE_BY_FILENAME | MODE_WRITER),
73 #endif
74 
75     // Apple platform
76 #ifdef HAVE_AVFOUNDATION
77     DECLARE_STATIC_BACKEND(CAP_AVFOUNDATION, "AVFOUNDATION", MODE_CAPTURE_ALL | MODE_WRITER, create_AVFoundation_capture_file, create_AVFoundation_capture_cam, create_AVFoundation_writer),
78 #endif
79 
80     // Windows
81 #ifdef WINRT_VIDEO
82     DECLARE_STATIC_BACKEND(CAP_WINRT, "WINRT", MODE_CAPTURE_BY_INDEX, 0, create_WRT_capture, 0),
83 #endif
84 
85 #ifdef HAVE_MSMF
86     DECLARE_STATIC_BACKEND(CAP_MSMF, "MSMF", MODE_CAPTURE_ALL | MODE_WRITER, cvCreateCapture_MSMF, cvCreateCapture_MSMF, cvCreateVideoWriter_MSMF),
87 #elif defined(ENABLE_PLUGINS) && defined(_WIN32)
88     DECLARE_DYNAMIC_BACKEND(CAP_MSMF, "MSMF", MODE_CAPTURE_ALL | MODE_WRITER),
89 #endif
90 
91 #ifdef HAVE_DSHOW
92     DECLARE_STATIC_BACKEND(CAP_DSHOW, "DSHOW", MODE_CAPTURE_BY_INDEX, 0, create_DShow_capture, 0),
93 #endif
94 
95     // Linux, some Unix
96 #if defined HAVE_CAMV4L2
97     DECLARE_STATIC_BACKEND(CAP_V4L2, "V4L2", MODE_CAPTURE_ALL, create_V4L_capture_file, create_V4L_capture_cam, 0),
98 #elif defined HAVE_VIDEOIO
99     DECLARE_STATIC_BACKEND(CAP_V4L, "V4L_BSD", MODE_CAPTURE_ALL, create_V4L_capture_file, create_V4L_capture_cam, 0),
100 #endif
101 
102 
103     // RGB-D universal
104 #ifdef HAVE_OPENNI2
105     DECLARE_STATIC_BACKEND(CAP_OPENNI2, "OPENNI2", MODE_CAPTURE_ALL, create_OpenNI2_capture_file, create_OpenNI2_capture_cam, 0),
106 #endif
107 
108 #ifdef HAVE_LIBREALSENSE
109     DECLARE_STATIC_BACKEND(CAP_REALSENSE, "INTEL_REALSENSE", MODE_CAPTURE_BY_INDEX, 0, create_RealSense_capture, 0),
110 #endif
111 
112     // OpenCV file-based only
113     DECLARE_STATIC_BACKEND(CAP_IMAGES, "CV_IMAGES", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, create_Images_capture, 0, create_Images_writer),
114     DECLARE_STATIC_BACKEND(CAP_OPENCV_MJPEG, "CV_MJPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER, createMotionJpegCapture, 0, createMotionJpegWriter),
115 
116     // special interfaces / stereo cameras / other SDKs
117 #if defined(HAVE_DC1394_2)
118     DECLARE_STATIC_BACKEND(CAP_FIREWIRE, "FIREWIRE", MODE_CAPTURE_BY_INDEX, 0, create_DC1394_capture, 0),
119 #endif
120     // GigE
121 #ifdef HAVE_PVAPI
122     DECLARE_STATIC_BACKEND(CAP_PVAPI, "PVAPI", MODE_CAPTURE_BY_INDEX, 0, create_PvAPI_capture, 0),
123 #endif
124 #ifdef HAVE_XIMEA
125     DECLARE_STATIC_BACKEND(CAP_XIAPI, "XIMEA", MODE_CAPTURE_ALL, create_XIMEA_capture_file, create_XIMEA_capture_cam, 0),
126 #endif
127 #ifdef HAVE_ARAVIS_API
128     DECLARE_STATIC_BACKEND(CAP_ARAVIS, "ARAVIS", MODE_CAPTURE_BY_INDEX, 0, create_Aravis_capture, 0),
129 #endif
130 
131 #ifdef HAVE_UEYE // uEye
132     DECLARE_STATIC_BACKEND(CAP_UEYE, "UEYE", MODE_CAPTURE_BY_INDEX, 0, create_ueye_camera, 0),
133 #elif defined(ENABLE_PLUGINS)
134     DECLARE_DYNAMIC_BACKEND(CAP_UEYE, "UEYE", MODE_CAPTURE_BY_INDEX),
135 #endif
136 
137 #ifdef HAVE_GPHOTO2
138     DECLARE_STATIC_BACKEND(CAP_GPHOTO2, "GPHOTO2", MODE_CAPTURE_ALL, createGPhoto2Capture, createGPhoto2Capture, 0),
139 #endif
140 #ifdef HAVE_XINE
141     DECLARE_STATIC_BACKEND(CAP_XINE, "XINE", MODE_CAPTURE_BY_FILENAME, createXINECapture, 0, 0),
142 #endif
143 #if defined(HAVE_ANDROID_MEDIANDK) || defined(HAVE_ANDROID_NATIVE_CAMERA)
144     DECLARE_STATIC_BACKEND(CAP_ANDROID, "ANDROID_NATIVE",
145 #ifdef HAVE_ANDROID_MEDIANDK
146                            MODE_CAPTURE_BY_FILENAME
147 #else
148                            0
149 #endif
150                            |
151 #ifdef HAVE_ANDROID_NATIVE_CAMERA
152                            MODE_CAPTURE_BY_INDEX,
153 #else
154                            0,
155 #endif
156 #ifdef HAVE_ANDROID_MEDIANDK
157                            createAndroidCapture_file,
158 #else
159                            0,
160 #endif
161 #ifdef HAVE_ANDROID_NATIVE_CAMERA
162                            createAndroidCapture_cam,
163 #else
164                            0,
165 #endif
166                            0),
167 #endif
168     // dropped backends: MIL, TYZX
169 };
170 
sortByPriority(const VideoBackendInfo & lhs,const VideoBackendInfo & rhs)171 bool sortByPriority(const VideoBackendInfo &lhs, const VideoBackendInfo &rhs)
172 {
173     return lhs.priority > rhs.priority;
174 }
175 
176 /** @brief Manages list of enabled backends
177  */
178 class VideoBackendRegistry
179 {
180 protected:
181     std::vector<VideoBackendInfo> enabledBackends;
VideoBackendRegistry()182     VideoBackendRegistry()
183     {
184         const int N = sizeof(builtin_backends)/sizeof(builtin_backends[0]);
185         enabledBackends.assign(builtin_backends, builtin_backends + N);
186         for (int i = 0; i < N; i++)
187         {
188             VideoBackendInfo& info = enabledBackends[i];
189             info.priority = 1000 - i * 10;
190         }
191         CV_LOG_DEBUG(NULL, "VIDEOIO: Builtin backends(" << N << "): " << dumpBackends());
192         if (readPrioritySettings())
193         {
194             CV_LOG_INFO(NULL, "VIDEOIO: Updated backends priorities: " << dumpBackends());
195         }
196         int enabled = 0;
197         for (int i = 0; i < N; i++)
198         {
199             VideoBackendInfo& info = enabledBackends[enabled];
200             if (enabled != i)
201                 info = enabledBackends[i];
202             size_t param_priority = utils::getConfigurationParameterSizeT(cv::format("OPENCV_VIDEOIO_PRIORITY_%s", info.name).c_str(), (size_t)info.priority);
203             CV_Assert(param_priority == (size_t)(int)param_priority); // overflow check
204             if (param_priority > 0)
205             {
206                 info.priority = (int)param_priority;
207                 enabled++;
208             }
209             else
210             {
211                 CV_LOG_INFO(NULL, "VIDEOIO: Disable backend: " << info.name);
212             }
213         }
214         enabledBackends.resize(enabled);
215         CV_LOG_DEBUG(NULL, "VIDEOIO: Available backends(" << enabled << "): " << dumpBackends());
216         std::sort(enabledBackends.begin(), enabledBackends.end(), sortByPriority);
217         CV_LOG_INFO(NULL, "VIDEOIO: Enabled backends(" << enabled << ", sorted by priority): " << dumpBackends());
218     }
219 
tokenize_string(const std::string & input,char token)220     static std::vector<std::string> tokenize_string(const std::string& input, char token)
221     {
222         std::vector<std::string> result;
223         std::string::size_type prev_pos = 0, pos = 0;
224         while((pos = input.find(token, pos)) != std::string::npos)
225         {
226             result.push_back(input.substr(prev_pos, pos-prev_pos));
227             prev_pos = ++pos;
228         }
229         result.push_back(input.substr(prev_pos));
230         return result;
231     }
readPrioritySettings()232     bool readPrioritySettings()
233     {
234         bool hasChanges = false;
235         cv::String prioritized_backends = utils::getConfigurationParameterString("OPENCV_VIDEOIO_PRIORITY_LIST", NULL);
236         if (prioritized_backends.empty())
237             return hasChanges;
238         CV_LOG_INFO(NULL, "VIDEOIO: Configured priority list (OPENCV_VIDEOIO_PRIORITY_LIST): " << prioritized_backends);
239         const std::vector<std::string> names = tokenize_string(prioritized_backends, ',');
240         for (size_t i = 0; i < names.size(); i++)
241         {
242             const std::string& name = names[i];
243             bool found = false;
244             for (size_t k = 0; k < enabledBackends.size(); k++)
245             {
246                 VideoBackendInfo& info = enabledBackends[k];
247                 if (name == info.name)
248                 {
249                     info.priority = (int)(100000 + (names.size() - i) * 1000);
250                     CV_LOG_DEBUG(NULL, "VIDEOIO: New backend priority: '" << name << "' => " << info.priority);
251                     found = true;
252                     hasChanges = true;
253                     break;
254                 }
255             }
256             if (!found)
257             {
258                 CV_LOG_WARNING(NULL, "VIDEOIO: Can't prioritize unknown/unavailable backend: '" << name << "'");
259             }
260         }
261         return hasChanges;
262     }
263 public:
dumpBackends() const264     std::string dumpBackends() const
265     {
266         std::ostringstream os;
267         for (size_t i = 0; i < enabledBackends.size(); i++)
268         {
269             if (i > 0) os << "; ";
270             const VideoBackendInfo& info = enabledBackends[i];
271             os << info.name << '(' << info.priority << ')';
272         }
273         return os.str();
274     }
275 
getInstance()276     static VideoBackendRegistry& getInstance()
277     {
278         static VideoBackendRegistry g_instance;
279         return g_instance;
280     }
281 
getEnabledBackends() const282     inline std::vector<VideoBackendInfo> getEnabledBackends() const { return enabledBackends; }
283 
getAvailableBackends_CaptureByIndex() const284     inline std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex() const
285     {
286         std::vector<VideoBackendInfo> result;
287         for (size_t i = 0; i < enabledBackends.size(); i++)
288         {
289             const VideoBackendInfo& info = enabledBackends[i];
290             if (info.mode & MODE_CAPTURE_BY_INDEX)
291                 result.push_back(info);
292         }
293         return result;
294     }
getAvailableBackends_CaptureByFilename() const295     inline std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename() const
296     {
297         std::vector<VideoBackendInfo> result;
298         for (size_t i = 0; i < enabledBackends.size(); i++)
299         {
300             const VideoBackendInfo& info = enabledBackends[i];
301             if (info.mode & MODE_CAPTURE_BY_FILENAME)
302                 result.push_back(info);
303         }
304         return result;
305     }
getAvailableBackends_Writer() const306     inline std::vector<VideoBackendInfo> getAvailableBackends_Writer() const
307     {
308         std::vector<VideoBackendInfo> result;
309         for (size_t i = 0; i < enabledBackends.size(); i++)
310         {
311             const VideoBackendInfo& info = enabledBackends[i];
312             if (info.mode & MODE_WRITER)
313                 result.push_back(info);
314         }
315         return result;
316     }
317 };
318 
319 } // namespace
320 
321 namespace videoio_registry {
322 
getAvailableBackends_CaptureByIndex()323 std::vector<VideoBackendInfo> getAvailableBackends_CaptureByIndex()
324 {
325     const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex();
326     return result;
327 }
getAvailableBackends_CaptureByFilename()328 std::vector<VideoBackendInfo> getAvailableBackends_CaptureByFilename()
329 {
330     const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename();
331     return result;
332 }
getAvailableBackends_Writer()333 std::vector<VideoBackendInfo> getAvailableBackends_Writer()
334 {
335     const std::vector<VideoBackendInfo> result = VideoBackendRegistry::getInstance().getAvailableBackends_Writer();
336     return result;
337 }
338 
getBackendName(VideoCaptureAPIs api)339 cv::String getBackendName(VideoCaptureAPIs api)
340 {
341     if (api == CAP_ANY)
342         return "CAP_ANY";  // special case, not a part of backends list
343     const int N = sizeof(builtin_backends)/sizeof(builtin_backends[0]);
344     for (size_t i = 0; i < N; i++)
345     {
346         const VideoBackendInfo& backend = builtin_backends[i];
347         if (backend.id == api)
348             return backend.name;
349     }
350     return cv::format("UnknownVideoAPI(%d)", (int)api);
351 }
352 
getBackends()353 std::vector<VideoCaptureAPIs> getBackends()
354 {
355     std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getEnabledBackends();
356     std::vector<VideoCaptureAPIs> result;
357     for (size_t i = 0; i < backends.size(); i++)
358         result.push_back((VideoCaptureAPIs)backends[i].id);
359     return result;
360 }
361 
getCameraBackends()362 std::vector<VideoCaptureAPIs> getCameraBackends()
363 {
364     const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex();
365     std::vector<VideoCaptureAPIs> result;
366     for (size_t i = 0; i < backends.size(); i++)
367         result.push_back((VideoCaptureAPIs)backends[i].id);
368     return result;
369 
370 }
371 
getStreamBackends()372 std::vector<VideoCaptureAPIs> getStreamBackends()
373 {
374     const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename();
375     std::vector<VideoCaptureAPIs> result;
376     for (size_t i = 0; i < backends.size(); i++)
377         result.push_back((VideoCaptureAPIs)backends[i].id);
378     return result;
379 
380 }
381 
getWriterBackends()382 std::vector<VideoCaptureAPIs> getWriterBackends()
383 {
384     const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_Writer();
385     std::vector<VideoCaptureAPIs> result;
386     for (size_t i = 0; i < backends.size(); i++)
387         result.push_back((VideoCaptureAPIs)backends[i].id);
388     return result;
389 }
390 
hasBackend(VideoCaptureAPIs api)391 bool hasBackend(VideoCaptureAPIs api)
392 {
393     std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getEnabledBackends();
394     for (size_t i = 0; i < backends.size(); i++)
395     {
396         const VideoBackendInfo& info = backends[i];
397         if (api == info.id)
398         {
399             CV_Assert(!info.backendFactory.empty());
400             return !info.backendFactory->getBackend().empty();
401         }
402     }
403     return false;
404 }
405 
isBackendBuiltIn(VideoCaptureAPIs api)406 bool isBackendBuiltIn(VideoCaptureAPIs api)
407 {
408     std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getEnabledBackends();
409     for (size_t i = 0; i < backends.size(); i++)
410     {
411         const VideoBackendInfo& info = backends[i];
412         if (api == info.id)
413         {
414             CV_Assert(!info.backendFactory.empty());
415             return info.backendFactory->isBuiltIn();
416         }
417     }
418     return false;
419 }
420 
getCameraBackendPluginVersion(VideoCaptureAPIs api,CV_OUT int & version_ABI,CV_OUT int & version_API)421 std::string getCameraBackendPluginVersion(VideoCaptureAPIs api,
422     CV_OUT int& version_ABI,
423     CV_OUT int& version_API
424 )
425 {
426     const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByIndex();
427     for (size_t i = 0; i < backends.size(); i++)
428     {
429         const VideoBackendInfo& info = backends[i];
430         if (api == info.id)
431         {
432             CV_Assert(!info.backendFactory.empty());
433             CV_Assert(!info.backendFactory->isBuiltIn());
434             return getCapturePluginVersion(info.backendFactory, version_ABI, version_API);
435         }
436     }
437     CV_Error(Error::StsError, "Unknown or wrong backend ID");
438 }
439 
getStreamBackendPluginVersion(VideoCaptureAPIs api,CV_OUT int & version_ABI,CV_OUT int & version_API)440 std::string getStreamBackendPluginVersion(VideoCaptureAPIs api,
441     CV_OUT int& version_ABI,
442     CV_OUT int& version_API
443 )
444 {
445     const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename();
446     for (size_t i = 0; i < backends.size(); i++)
447     {
448         const VideoBackendInfo& info = backends[i];
449         if (api == info.id)
450         {
451             CV_Assert(!info.backendFactory.empty());
452             CV_Assert(!info.backendFactory->isBuiltIn());
453             return getCapturePluginVersion(info.backendFactory, version_ABI, version_API);
454         }
455     }
456     CV_Error(Error::StsError, "Unknown or wrong backend ID");
457 }
458 
459 
460 /** @brief Returns description and ABI/API version of videoio plugin's writer interface */
getWriterBackendPluginVersion(VideoCaptureAPIs api,CV_OUT int & version_ABI,CV_OUT int & version_API)461 std::string getWriterBackendPluginVersion(VideoCaptureAPIs api,
462     CV_OUT int& version_ABI,
463     CV_OUT int& version_API
464 )
465 {
466     const std::vector<VideoBackendInfo> backends = VideoBackendRegistry::getInstance().getAvailableBackends_Writer();
467     for (size_t i = 0; i < backends.size(); i++)
468     {
469         const VideoBackendInfo& info = backends[i];
470         if (api == info.id)
471         {
472             CV_Assert(!info.backendFactory.empty());
473             CV_Assert(!info.backendFactory->isBuiltIn());
474             return getWriterPluginVersion(info.backendFactory, version_ABI, version_API);
475         }
476     }
477     CV_Error(Error::StsError, "Unknown or wrong backend ID");
478 }
479 
480 
481 } // namespace registry
482 
483 } // namespace
484