From cd9e43704e0082c0fdd4bdef2d2631daa531fe2e Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 21 May 2018 14:06:31 +0000 Subject: [PATCH] videoio: backends priority list --- modules/videoio/CMakeLists.txt | 2 + modules/videoio/src/cap.cpp | 673 +++------------------- modules/videoio/src/cap_mjpeg_encoder.cpp | 5 +- modules/videoio/src/precomp.hpp | 7 +- modules/videoio/src/videoio_c.cpp | 152 +++++ modules/videoio/src/videoio_registry.cpp | 637 ++++++++++++++++++++ modules/videoio/src/videoio_registry.hpp | 43 ++ modules/videoio/test/test_ffmpeg.cpp | 12 +- 8 files changed, 944 insertions(+), 587 deletions(-) create mode 100644 modules/videoio/src/videoio_c.cpp create mode 100644 modules/videoio/src/videoio_registry.cpp create mode 100644 modules/videoio/src/videoio_registry.hpp diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt index 02d2bd830f..c6fee91924 100644 --- a/modules/videoio/CMakeLists.txt +++ b/modules/videoio/CMakeLists.txt @@ -20,6 +20,8 @@ set(videoio_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/precomp.hpp ) set(videoio_srcs + ${CMAKE_CURRENT_LIST_DIR}/src/videoio_registry.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/videoio_c.cpp ${CMAKE_CURRENT_LIST_DIR}/src/cap.cpp ${CMAKE_CURRENT_LIST_DIR}/src/cap_images.cpp ${CMAKE_CURRENT_LIST_DIR}/src/cap_mjpeg_encoder.cpp diff --git a/modules/videoio/src/cap.cpp b/modules/videoio/src/cap.cpp index 25e1208ad6..693f32e6f2 100644 --- a/modules/videoio/src/cap.cpp +++ b/modules/videoio/src/cap.cpp @@ -40,39 +40,10 @@ //M*/ #include "precomp.hpp" -#include -using namespace std; -#include "cap_intelperc.hpp" -#include "cap_dshow.hpp" - -#ifdef HAVE_MFX -#include "cap_mfx_reader.hpp" -#include "cap_mfx_writer.hpp" -#endif - -// All WinRT versions older than 8.0 should provide classes used for video support -#if defined(WINRT) && !defined(WINRT_8_0) && defined(__cplusplus_winrt) -# include "cap_winrt_capture.hpp" -# include "cap_winrt_bridge.hpp" -# define WINRT_VIDEO -#endif - -#if defined _M_X64 && defined _MSC_VER && !defined CV_ICC -#pragma optimize("",off) -#pragma warning(disable: 4748) -#endif -#if defined(__clang__) -#pragma clang diagnostic ignored "-Wimplicit-fallthrough" -#endif -#if defined(__GNUC__) && __GNUC__ >= 7 -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" -#endif +#include "videoio_registry.hpp" -using namespace cv; - -namespace cv -{ +namespace cv { template<> void DefaultDeleter::operator ()(CvCapture* obj) const { cvReleaseCapture(&obj); } @@ -80,531 +51,7 @@ template<> void DefaultDeleter::operator ()(CvCapture* obj) const template<> void DefaultDeleter::operator ()(CvVideoWriter* obj) const { cvReleaseVideoWriter(&obj); } -} - -/************************* Reading AVIs & Camera data **************************/ - -static inline double icvGetCaptureProperty( const CvCapture* capture, int id ) -{ - return capture ? capture->getProperty(id) : 0; -} - -CV_IMPL void cvReleaseCapture( CvCapture** pcapture ) -{ - if( pcapture && *pcapture ) - { - delete *pcapture; - *pcapture = 0; - } -} - -CV_IMPL IplImage* cvQueryFrame( CvCapture* capture ) -{ - if(!capture) - return 0; - if(!capture->grabFrame()) - return 0; - return capture->retrieveFrame(0); -} - - -CV_IMPL int cvGrabFrame( CvCapture* capture ) -{ - return capture ? capture->grabFrame() : 0; -} - -CV_IMPL IplImage* cvRetrieveFrame( CvCapture* capture, int idx ) -{ - return capture ? capture->retrieveFrame(idx) : 0; -} - -CV_IMPL double cvGetCaptureProperty( CvCapture* capture, int id ) -{ - return icvGetCaptureProperty(capture, id); -} - -CV_IMPL int cvSetCaptureProperty( CvCapture* capture, int id, double value ) -{ - return capture ? capture->setProperty(id, value) : 0; -} - -CV_IMPL int cvGetCaptureDomain( CvCapture* capture) -{ - return capture ? capture->getCaptureDomain() : 0; -} - -static bool get_capture_debug_flag() -{ - static bool initialized = false; - static bool flag = false; - if (!initialized) - { -#ifndef NO_GETENV - flag = getenv("OPENCV_VIDEOCAPTURE_DEBUG") ? true : false; // TODO Use getBoolParameter -#endif - initialized = true; - } - return flag; -} - -#define TRY_OPEN(capture, backend_func) \ -{ \ - if (!capture) \ - CV_TRY { \ - if (get_capture_debug_flag()) fprintf(stderr, "VIDEOIO(%s): trying ...\n", #backend_func); \ - capture = backend_func; \ - if (get_capture_debug_flag()) fprintf(stderr, "VIDEOIO(%s): result=%p ...\n", #backend_func, capture); \ - } CV_CATCH (cv::Exception, e) { \ - fprintf(stderr, "VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what()); \ - } CV_CATCH (std::exception, e) { \ - fprintf(stderr, "VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what()); \ - } CV_CATCH_ALL { \ - fprintf(stderr, "VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func); \ - } \ -} - - -/** - * Camera dispatching method: index is the camera number. - * If given an index from 0 to 99, it tries to find the first - * API that can access a given camera index. - * Add multiples of 100 to select an API. - */ -CV_IMPL CvCapture * cvCreateCameraCapture (int index) -{ - // interpret preferred interface (0 = autodetect) - int pref = (index / 100) * 100; - - // remove pref from index - index -= pref; - // local variable to memorize the captured device - CvCapture *capture = 0; - - switch (pref) - { - default: - // user specified an API we do not know - // bail out to let the user know that it is not available - if (pref) break; - - case CAP_VFW: // or CAP_V4L or CAP_V4L2 -#ifdef HAVE_VFW - TRY_OPEN(capture, cvCreateCameraCapture_VFW(index)) -#endif - -#if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO - TRY_OPEN(capture, cvCreateCameraCapture_V4L(index)) -#endif - - if (pref) break; // CAP_VFW or CAP_V4L or CAP_V4L2 - - case CAP_FIREWIRE: -#ifdef HAVE_DC1394_2 - TRY_OPEN(capture, cvCreateCameraCapture_DC1394_2(index)) -#endif - -#ifdef HAVE_DC1394 - TRY_OPEN(capture, cvCreateCameraCapture_DC1394(index)) -#endif - -#ifdef HAVE_CMU1394 - TRY_OPEN(capture, cvCreateCameraCapture_CMU(index)) -#endif - - if (pref) break; // CAP_FIREWIRE - -#ifdef HAVE_MIL - case CAP_MIL: - TRY_OPEN(capture, cvCreateCameraCapture_MIL(index)) - if (pref) break; -#endif - -#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) - case CAP_QT: - TRY_OPEN(capture, cvCreateCameraCapture_QT(index)) - if (pref) break; -#endif - -#ifdef HAVE_UNICAP - case CAP_UNICAP: - TRY_OPEN(capture, cvCreateCameraCapture_Unicap(index)) - if (pref) break; -#endif - -#ifdef HAVE_PVAPI - case CAP_PVAPI: - TRY_OPEN(capture, cvCreateCameraCapture_PvAPI(index)) - if (pref) break; -#endif - -#ifdef HAVE_OPENNI - case CAP_OPENNI: - TRY_OPEN(capture, cvCreateCameraCapture_OpenNI(index)) - if (pref) break; -#endif - -#ifdef HAVE_OPENNI2 - case CAP_OPENNI2: - TRY_OPEN(capture, cvCreateCameraCapture_OpenNI2(index)) - if (pref) break; -#endif - -#ifdef HAVE_XIMEA - case CAP_XIAPI: - TRY_OPEN(capture, cvCreateCameraCapture_XIMEA(index)) - if (pref) break; -#endif - -#ifdef HAVE_AVFOUNDATION - case CAP_AVFOUNDATION: - TRY_OPEN(capture, cvCreateCameraCapture_AVFoundation(index)) - if (pref) break; -#endif - -#ifdef HAVE_GIGE_API - case CAP_GIGANETIX: - TRY_OPEN(capture, cvCreateCameraCapture_Giganetix(index)) - if (pref) break; // CAP_GIGANETIX -#endif - -#ifdef HAVE_ARAVIS_API - case CAP_ARAVIS: - TRY_OPEN(capture, cvCreateCameraCapture_Aravis(index)) - if (pref) break; -#endif - } - - return capture; -} - -/** - * Videoreader dispatching method: it tries to find the first - * API that can access a given filename. - */ -CV_IMPL CvCapture * cvCreateFileCaptureWithPreference (const char * filename, int apiPreference) -{ - CvCapture * result = 0; - - switch(apiPreference) { - default: - // user specified an API we do not know - // bail out to let the user know that it is not available - if (apiPreference) break; - -#if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO - case CAP_V4L: - TRY_OPEN(result, cvCreateCameraCapture_V4L(filename)) - if (apiPreference) break; -#endif - -#ifdef HAVE_VFW - case CAP_VFW: - TRY_OPEN(result, cvCreateFileCapture_VFW (filename)) - if (apiPreference) break; -#endif - -#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) - case CAP_QT: - TRY_OPEN(result, cvCreateFileCapture_QT (filename)) - if (apiPreference) break; -#endif - -#ifdef HAVE_AVFOUNDATION - case CAP_AVFOUNDATION: - TRY_OPEN(result, cvCreateFileCapture_AVFoundation (filename)) - if (apiPreference) break; -#endif - -#ifdef HAVE_OPENNI - case CAP_OPENNI: - TRY_OPEN(result, cvCreateFileCapture_OpenNI (filename)) - if (apiPreference) break; -#endif - -#ifdef HAVE_OPENNI2 - case CAP_OPENNI2: - TRY_OPEN(result, cvCreateFileCapture_OpenNI2 (filename)) - if (apiPreference) break; -#endif -#ifdef HAVE_XIMEA - case CAP_XIAPI: - TRY_OPEN(result, cvCreateCameraCapture_XIMEA(filename)) - if (apiPreference) break; -#endif - case CAP_IMAGES: - TRY_OPEN(result, cvCreateFileCapture_Images (filename)) - } - - return result; -} - -CV_IMPL CvCapture * cvCreateFileCapture (const char * filename) -{ - return cvCreateFileCaptureWithPreference(filename, CAP_ANY); -} - -/** - * Videowriter dispatching method: it tries to find the first - * API that can write a given stream. - */ -static CvVideoWriter* cvCreateVideoWriterWithPreference(const char* filename, int apiPreference, int fourcc, - double fps, CvSize frameSize, int is_color ) -{ - CV_UNUSED(frameSize); - CV_UNUSED(is_color); - - CvVideoWriter *result = 0; - - if(!fourcc || !fps) - TRY_OPEN(result, cvCreateVideoWriter_Images(filename)) - - CV_Assert(result || fps != 0); - - switch(apiPreference) - { - default: - //exit if the specified API is unavaliable - if (apiPreference != CAP_ANY) break; - #ifdef HAVE_VFW - case CAP_VFW: - TRY_OPEN(result, cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, is_color)) - if (apiPreference != CAP_ANY) break; - #endif - #ifdef HAVE_AVFOUNDATION - case CAP_AVFOUNDATION: - TRY_OPEN(result, cvCreateVideoWriter_AVFoundation(filename, fourcc, fps, frameSize, is_color)) - if (apiPreference != CAP_ANY) break; - #endif - #if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) - case(CAP_QT): - TRY_OPEN(result, cvCreateVideoWriter_QT(filename, fourcc, fps, frameSize, is_color)) - if (apiPreference != CAP_ANY) break; - #endif - #ifdef HAVE_GSTREAMER - case CAP_GSTREAMER: - TRY_OPEN(result, cvCreateVideoWriter_GStreamer (filename, fourcc, fps, frameSize, is_color)) - if (apiPreference != CAP_ANY) break; - #endif - case CAP_IMAGES: - TRY_OPEN(result, cvCreateVideoWriter_Images(filename)) - if (apiPreference != CAP_ANY) break; - } - - return result; -} - -CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char* filename, int fourcc, - double fps, CvSize frameSize, int is_color ) -{ - return cvCreateVideoWriterWithPreference(filename, CAP_ANY, fourcc, fps, frameSize, is_color); -} - -CV_IMPL int cvWriteFrame( CvVideoWriter* writer, const IplImage* image ) -{ - return writer ? writer->writeFrame(image) : 0; -} - -CV_IMPL void cvReleaseVideoWriter( CvVideoWriter** pwriter ) -{ - if( pwriter && *pwriter ) - { - delete *pwriter; - *pwriter = 0; - } -} - -namespace cv -{ - -static Ptr IVideoCapture_create(int index) -{ - int domains[] = - { -#ifdef HAVE_GSTREAMER - CAP_GSTREAMER, -#endif -#ifdef HAVE_MSMF - CAP_MSMF, -#endif -#ifdef HAVE_DSHOW - CAP_DSHOW, -#endif -#ifdef HAVE_INTELPERC - CAP_INTELPERC, -#endif -#ifdef WINRT_VIDEO - CAP_WINRT, -#endif -#ifdef HAVE_GPHOTO2 - CAP_GPHOTO2, -#endif - -1, -1 - }; - - // interpret preferred interface (0 = autodetect) - int pref = (index / 100) * 100; - if (pref) - { - domains[0]=pref; - index %= 100; - domains[1]=-1; - } - - // try every possibly installed camera API - for (int i = 0; domains[i] >= 0; i++) - { -#if defined(HAVE_GSTREAMER) || \ - defined(HAVE_MSMF) || \ - defined(HAVE_DSHOW) || \ - defined(HAVE_INTELPERC) || \ - defined(WINRT_VIDEO) || \ - defined(HAVE_GPHOTO2) || \ - (0) - Ptr capture; - - switch (domains[i]) - { -#ifdef HAVE_GSTREAMER - case CAP_GSTREAMER: - capture = createGStreamerCapture(index); - break; -#endif -#ifdef HAVE_MSMF - case CAP_MSMF: - capture = cvCreateCapture_MSMF(index); - break; // CAP_MSMF -#endif -#ifdef HAVE_DSHOW - case CAP_DSHOW: - capture = makePtr(index); - break; // CAP_DSHOW -#endif -#ifdef HAVE_INTELPERC - case CAP_INTELPERC: - capture = makePtr(); - break; // CAP_INTEL_PERC -#endif -#ifdef WINRT_VIDEO - case CAP_WINRT: - capture = Ptr(new cv::VideoCapture_WinRT(index)); - if (capture) - return capture; - break; // CAP_WINRT -#endif -#ifdef HAVE_GPHOTO2 - case CAP_GPHOTO2: - capture = createGPhoto2Capture(index); - break; -#endif - } - if (capture && capture->isOpened()) - return capture; -#endif - } - - // failed open a camera - return Ptr(); -} - - -static Ptr IVideoCapture_create(const String& filename, int apiPreference) -{ - bool useAny = (apiPreference == CAP_ANY); - Ptr capture; -#ifdef HAVE_FFMPEG - if (useAny || apiPreference == CAP_FFMPEG) - { - capture = cvCreateFileCapture_FFMPEG_proxy(filename); - if (capture && capture->isOpened()) - return capture; - } -#endif -#ifdef HAVE_GSTREAMER - if (useAny || apiPreference == CAP_GSTREAMER) - { - capture = createGStreamerCapture(filename); - if (capture && capture->isOpened()) - return capture; - } -#endif -#ifdef HAVE_XINE - if (useAny || apiPreference == CAP_XINE) - { - capture = createXINECapture(filename.c_str()); - if (capture && capture->isOpened()) - return capture; - } -#endif -#ifdef HAVE_MSMF - if (useAny || apiPreference == CAP_MSMF) - { - capture = cvCreateCapture_MSMF(filename); - if (capture && capture->isOpened()) - return capture; - } -#endif -#ifdef HAVE_GPHOTO2 - if (useAny || apiPreference == CAP_GPHOTO2) - { - capture = createGPhoto2Capture(filename); - if (capture && capture->isOpened()) - return capture; - } -#endif -#ifdef HAVE_MFX - if (useAny || apiPreference == CAP_INTEL_MFX) - { - capture = makePtr(filename); - if (capture && capture->isOpened()) - return capture; - } -#endif - if (useAny || apiPreference == CAP_OPENCV_MJPEG) - { - capture = createMotionJpegCapture(filename); - if (capture && capture->isOpened()) - return capture; - } - if (capture && !capture->isOpened()) - capture.release(); - return capture; -} - -static Ptr IVideoWriter_create(const String& filename, int apiPreference, int _fourcc, double fps, Size frameSize, bool isColor) -{ - Ptr iwriter; -#ifdef HAVE_FFMPEG - if (apiPreference == CAP_FFMPEG || apiPreference == CAP_ANY) - { - iwriter = cvCreateVideoWriter_FFMPEG_proxy(filename, _fourcc, fps, frameSize, isColor); - if (!iwriter.empty()) - return iwriter; - } -#endif -#ifdef HAVE_MSMF - if (apiPreference == CAP_MSMF || apiPreference == CAP_ANY) - { - iwriter = cvCreateVideoWriter_MSMF(filename, _fourcc, fps, frameSize, isColor); - if (!iwriter.empty()) - return iwriter; - } -#endif -#ifdef HAVE_MFX - if (apiPreference == CAP_INTEL_MFX || apiPreference == CAP_ANY) - { - iwriter = VideoWriter_IntelMFX::create(filename, _fourcc, fps, frameSize, isColor); - if (!iwriter.empty()) - return iwriter; - } -#endif - - if( (apiPreference == CAP_OPENCV_MJPEG || apiPreference == CAP_ANY) - && _fourcc == CV_FOURCC('M', 'J', 'P', 'G') ) - iwriter = createMotionJpegWriter(filename, fps, frameSize, isColor); - - return iwriter; -} VideoCapture::VideoCapture() {} @@ -640,12 +87,30 @@ bool VideoCapture::open(const String& filename, int apiPreference) CV_TRACE_FUNCTION(); if (isOpened()) release(); - icap = IVideoCapture_create(filename, apiPreference); - if (!icap.empty()) - return true; - cap.reset(cvCreateFileCaptureWithPreference(filename.c_str(), apiPreference)); - return isOpened(); + const std::vector backends = cv::videoio_registry::getAvailableBackends_CaptureByFilename(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + if (apiPreference == CAP_ANY || apiPreference == info.id) + { + CvCapture* capture = NULL; + VideoCapture_create(capture, icap, info.id, filename); + if (!icap.empty()) + { + if (icap->isOpened()) + return true; + icap.release(); + } + if (capture) + { + cap.reset(capture); + // assume it is opened + return true; + } + } + } + return false; } bool VideoCapture::open(const String& filename) @@ -655,28 +120,56 @@ bool VideoCapture::open(const String& filename) return open(filename, CAP_ANY); } -bool VideoCapture::open(int index) +bool VideoCapture::open(int cameraNum, int apiPreference) { CV_TRACE_FUNCTION(); if (isOpened()) release(); - icap = IVideoCapture_create(index); - if (!icap.empty()) - return true; - cap.reset(cvCreateCameraCapture(index)); - return isOpened(); + + const std::vector backends = cv::videoio_registry::getAvailableBackends_CaptureByIndex(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + if (apiPreference == CAP_ANY || apiPreference == info.id) + { + CvCapture* capture = NULL; + VideoCapture_create(capture, icap, info.id, cameraNum); + if (!icap.empty()) + { + if (icap->isOpened()) + return true; + icap.release(); + } + if (capture) + { + cap.reset(capture); + // assume it is opened + return true; + } + } + } + return false; } -bool VideoCapture::open(int cameraNum, int apiPreference) + +bool VideoCapture::open(int index) { CV_TRACE_FUNCTION(); - cameraNum = cameraNum + apiPreference; - return open(cameraNum); + // interpret preferred interface (0 = autodetect) + int backendID = (index / 100) * 100; + if (backendID) + { + index %= 100; + } + + return open(index, backendID); } bool VideoCapture::isOpened() const { - return (!cap.empty() || !icap.empty()); + if (!icap.empty()) + return icap->isOpened(); + return !icap.empty(); // legacy interface doesn't support closed files } void VideoCapture::release() @@ -732,6 +225,7 @@ bool VideoCapture::read(OutputArray image) VideoCapture& VideoCapture::operator >> (Mat& image) { #ifdef WINRT_VIDEO + // FIXIT grab/retrieve methods() should work too if (grab()) { if (retrieve(image)) @@ -753,7 +247,6 @@ VideoCapture& VideoCapture::operator >> (Mat& image) #else read(image); #endif - return *this; } @@ -776,10 +269,14 @@ double VideoCapture::get(int propId) const { if (!icap.empty()) return icap->getProperty(propId); - return icvGetCaptureProperty(cap, propId); + return cap ? cap->getProperty(propId) : 0; } +//================================================================================================= + + + VideoWriter::VideoWriter() {} @@ -815,11 +312,30 @@ bool VideoWriter::open(const String& filename, int apiPreference, int _fourcc, d CV_INSTRUMENT_REGION() if (isOpened()) release(); - iwriter = IVideoWriter_create(filename, apiPreference, _fourcc, fps, frameSize, isColor); - if (!iwriter.empty()) - return true; - writer.reset(cvCreateVideoWriterWithPreference(filename.c_str(), apiPreference, _fourcc, fps, frameSize, isColor)); - return isOpened(); + + const std::vector backends = cv::videoio_registry::getAvailableBackends_Writer(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + if (apiPreference == CAP_ANY || apiPreference == info.id) + { + CvVideoWriter* writer_ = NULL; + VideoWriter_create(writer_, iwriter, info.id, filename, _fourcc, fps, frameSize, isColor); + if (!iwriter.empty()) + { + if (iwriter->isOpened()) + return true; + iwriter.release(); + } + if (writer_) + { + // assume it is opened + writer.reset(writer_); + return true; + } + } + } + return false; } bool VideoWriter::isOpened() const @@ -863,9 +379,10 @@ VideoWriter& VideoWriter::operator << (const Mat& image) return *this; } +// FIXIT OpenCV 4.0: make inline int VideoWriter::fourcc(char c1, char c2, char c3, char c4) { return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24); } -} +} // namespace diff --git a/modules/videoio/src/cap_mjpeg_encoder.cpp b/modules/videoio/src/cap_mjpeg_encoder.cpp index b564f608b9..fb1ded4997 100644 --- a/modules/videoio/src/cap_mjpeg_encoder.cpp +++ b/modules/videoio/src/cap_mjpeg_encoder.cpp @@ -1530,8 +1530,11 @@ void MotionJpegWriter::writeFrameData( const uchar* data, int step, int colorspa } -Ptr createMotionJpegWriter( const String& filename, double fps, Size frameSize, bool iscolor ) +Ptr createMotionJpegWriter(const String& filename, int fourcc, double fps, Size frameSize, bool iscolor) { + if (fourcc != CV_FOURCC('M', 'J', 'P', 'G')) + return Ptr(); + Ptr iwriter = makePtr(filename, fps, frameSize, iscolor); if( !iwriter->isOpened() ) iwriter.release(); diff --git a/modules/videoio/src/precomp.hpp b/modules/videoio/src/precomp.hpp index c08a224b05..a664aa7448 100644 --- a/modules/videoio/src/precomp.hpp +++ b/modules/videoio/src/precomp.hpp @@ -47,6 +47,9 @@ #include "opencv2/core/utility.hpp" #include "opencv2/core/private.hpp" +#include +#include + #include "opencv2/imgcodecs.hpp" #include "opencv2/imgproc.hpp" @@ -59,7 +62,7 @@ #include #include #include -#include +#include // FIXIT remove this #if defined _WIN32 || defined WINCE #if !defined _WIN32_WINNT @@ -178,7 +181,7 @@ namespace cv }; Ptr createMotionJpegCapture(const String& filename); - Ptr createMotionJpegWriter( const String& filename, double fps, Size frameSize, bool iscolor ); + Ptr createMotionJpegWriter(const String& filename, int fourcc, double fps, Size frameSize, bool iscolor); Ptr createGPhoto2Capture(int index); Ptr createGPhoto2Capture(const String& deviceName); diff --git a/modules/videoio/src/videoio_c.cpp b/modules/videoio/src/videoio_c.cpp new file mode 100644 index 0000000000..59a45225bd --- /dev/null +++ b/modules/videoio/src/videoio_c.cpp @@ -0,0 +1,152 @@ +// 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 "precomp.hpp" + +#include "videoio_registry.hpp" + +using namespace cv; + +// Legacy C-like API + +CV_IMPL CvCapture* cvCreateCameraCapture(int index) +{ + // interpret preferred interface (0 = autodetect) + int apiPreference = (index / 100) * 100; + if (apiPreference) + { + index %= 100; + } + + const std::vector backends = cv::videoio_registry::getAvailableBackends_CaptureByIndex(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + if (apiPreference == CAP_ANY || apiPreference == info.id) + { + CvCapture* capture = NULL; + Ptr icap; // unused + VideoCapture_create(capture, icap, info.id, index); + if (capture) + { + return capture; + } + if (!icap.empty()) + { + CV_LOG_WARNING(NULL, "cvCreateFileCaptureWithPreference: backend " << info.name << " doesn't support legacy API anymore.") + } + } + } + return NULL; +} + +CV_IMPL CvCapture* cvCreateFileCaptureWithPreference(const char* filename, int apiPreference) +{ + const std::vector backends = cv::videoio_registry::getAvailableBackends_CaptureByFilename(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + if (apiPreference == CAP_ANY || apiPreference == info.id) + { + CvCapture* capture = NULL; + Ptr icap; // unused + VideoCapture_create(capture, icap, info.id, filename); + if (capture) + { + return capture; + } + if (!icap.empty()) + { + CV_LOG_WARNING(NULL, "cvCreateFileCaptureWithPreference: backend " << info.name << " doesn't support legacy API anymore.") + } + } + } + return NULL; +} + +CV_IMPL CvCapture* cvCreateFileCapture(const char * filename) +{ + return cvCreateFileCaptureWithPreference(filename, CAP_ANY); +} + +CV_IMPL CvVideoWriter* cvCreateVideoWriter(const char* filename, int fourcc, + double fps, CvSize frameSize, int is_color) +{ + const std::vector backends = cv::videoio_registry::getAvailableBackends_Writer(); + for (size_t i = 0; i < backends.size(); i++) + { + const VideoBackendInfo& info = backends[i]; + { + CvVideoWriter* writer_ = NULL; + Ptr iwriter; // unused + VideoWriter_create(writer_, iwriter, info.id, filename, fourcc, fps, frameSize, is_color != 0); + if (writer_) + { + return writer_; + } + if (!iwriter.empty()) + { + CV_LOG_WARNING(NULL, "cvCreateVideoWriter: backend " << info.name << " doesn't support legacy API anymore.") + } + } + } + return NULL; +} + +CV_IMPL int cvWriteFrame(CvVideoWriter* writer, const IplImage* image) +{ + return writer ? writer->writeFrame(image) : 0; +} + +CV_IMPL void cvReleaseVideoWriter(CvVideoWriter** pwriter) +{ + if( pwriter && *pwriter ) + { + delete *pwriter; + *pwriter = 0; + } +} + +CV_IMPL void cvReleaseCapture(CvCapture** pcapture) +{ + if (pcapture && *pcapture) + { + delete *pcapture; + *pcapture = 0; + } +} + +CV_IMPL IplImage* cvQueryFrame(CvCapture* capture) +{ + if (!capture) + return 0; + if (!capture->grabFrame()) + return 0; + return capture->retrieveFrame(0); +} + +CV_IMPL int cvGrabFrame(CvCapture* capture) +{ + return capture ? capture->grabFrame() : 0; +} + +CV_IMPL IplImage* cvRetrieveFrame(CvCapture* capture, int idx) +{ + return capture ? capture->retrieveFrame(idx) : 0; +} + +CV_IMPL double cvGetCaptureProperty(CvCapture* capture, int id) +{ + return capture ? capture->getProperty(id) : 0; +} + +CV_IMPL int cvSetCaptureProperty(CvCapture* capture, int id, double value) +{ + return capture ? capture->setProperty(id, value) : 0; +} + +CV_IMPL int cvGetCaptureDomain(CvCapture* capture) +{ + return capture ? capture->getCaptureDomain() : 0; +} diff --git a/modules/videoio/src/videoio_registry.cpp b/modules/videoio/src/videoio_registry.cpp new file mode 100644 index 0000000000..484ebe30bc --- /dev/null +++ b/modules/videoio/src/videoio_registry.cpp @@ -0,0 +1,637 @@ +// 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 "precomp.hpp" + +#include "videoio_registry.hpp" + +#include "cap_intelperc.hpp" +#include "cap_dshow.hpp" + +#ifdef HAVE_MFX +#include "cap_mfx_reader.hpp" +#include "cap_mfx_writer.hpp" +#endif + +// All WinRT versions older than 8.0 should provide classes used for video support +#if defined(WINRT) && !defined(WINRT_8_0) && defined(__cplusplus_winrt) +# include "cap_winrt_capture.hpp" +# include "cap_winrt_bridge.hpp" +# define WINRT_VIDEO +#endif + +#if defined _M_X64 && defined _MSC_VER && !defined CV_ICC +#pragma optimize("",off) +#pragma warning(disable: 4748) +#endif + +using namespace cv; + +namespace cv +{ + +static bool param_VIDEOIO_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOIO_DEBUG", false); +static bool param_VIDEOCAPTURE_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOCAPTURE_DEBUG", false); +static bool param_VIDEOWRITER_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOWRITER_DEBUG", false); + +namespace { + +#define DECLARE_BACKEND(cap, name, mode) { cap, (BackendMode)(mode), 1000, name } + +/** Ordering guidelines: +- modern optimized, multi-platform libraries: ffmpeg, gstreamer, Media SDK +- platform specific universal SDK: WINRT, QTKIT/AVFOUNDATION, MSMF/VFW/DSHOW, V4L/V4L2 +- RGB-D: OpenNI/OpenNI2, INTELPERC/REALSENSE +- special OpenCV (file-based): "images", "mjpeg" +- special camera SDKs, including stereo: other special SDKs: FIREWIRE/1394, XIMEA/ARAVIS/GIGANETIX/PVAPI(GigE), UNICAP +- other: XINE, gphoto2, etc +*/ +static const struct VideoBackendInfo builtin_backends[] = +{ +#ifdef HAVE_FFMPEG + DECLARE_BACKEND(CAP_FFMPEG, "FFMPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER), +#endif +#ifdef HAVE_GSTREAMER + DECLARE_BACKEND(CAP_GSTREAMER, "GSTREAMER", MODE_CAPTURE_ALL | MODE_WRITER), +#endif +#ifdef HAVE_MFX // Media SDK + DECLARE_BACKEND(CAP_INTEL_MFX, "INTEL_MFX", MODE_CAPTURE_BY_FILENAME | MODE_WRITER), +#endif + + + // Apple platform +#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) + DECLARE_BACKEND(CAP_QT, "QUICKTIME", MODE_CAPTURE_ALL | MODE_WRITER), +#endif +#ifdef HAVE_AVFOUNDATION + DECLARE_BACKEND(CAP_AVFOUNDATION, "AVFOUNDATION", MODE_CAPTURE_ALL | MODE_WRITER), +#endif + + // Windows +#ifdef WINRT_VIDEO + DECLARE_BACKEND(CAP_WINRT, "WINRT", MODE_CAPTURE_BY_FILENAME), +#endif +#ifdef HAVE_MSMF + DECLARE_BACKEND(CAP_MSMF, "MSMF", MODE_CAPTURE_ALL | MODE_WRITER), +#endif +#ifdef HAVE_VFW + DECLARE_BACKEND(CAP_VFW, "VFW", MODE_CAPTURE_ALL | MODE_WRITER), +#endif +#ifdef HAVE_DSHOW + DECLARE_BACKEND(CAP_DSHOW, "DSHOW", MODE_CAPTURE_ALL), +#endif + + // Linux, some Unix +#if defined HAVE_CAMV4L2 + DECLARE_BACKEND(CAP_V4L2, "V4L2", MODE_CAPTURE_ALL), +#elif defined HAVE_LIBV4L || defined HAVE_CAMV4L + DECLARE_BACKEND(CAP_V4L, "V4L", MODE_CAPTURE_ALL), +#endif + + + // RGB-D universal +#ifdef HAVE_OPENNI + DECLARE_BACKEND(CAP_OPENNI, "OPENNI", MODE_CAPTURE_ALL), +#endif +#ifdef HAVE_OPENNI2 + DECLARE_BACKEND(CAP_OPENNI2, "OPENNI2", MODE_CAPTURE_ALL), +#endif +#ifdef HAVE_INTELPERC + DECLARE_BACKEND(CAP_INTELPERC, "INTEL_PERC", MODE_CAPTURE_ALL), +#endif + + // OpenCV file-based only + DECLARE_BACKEND(CAP_IMAGES, "CV_IMAGES", MODE_CAPTURE_BY_FILENAME | MODE_WRITER), + DECLARE_BACKEND(CAP_OPENCV_MJPEG, "CV_MJPEG", MODE_CAPTURE_BY_FILENAME | MODE_WRITER), + + // special interfaces / stereo cameras / other SDKs +#if defined(HAVE_DC1394_2) || defined(HAVE_DC1394) || defined(HAVE_CMU1394) + DECLARE_BACKEND(CAP_FIREWIRE, "FIREWIRE", MODE_CAPTURE_ALL), +#endif + // GigE +#ifdef HAVE_PVAPI + DECLARE_BACKEND(CAP_PVAPI, "PVAPI", MODE_CAPTURE_ALL), +#endif +#ifdef HAVE_XIMEA + DECLARE_BACKEND(CAP_XIAPI, "XIMEA", MODE_CAPTURE_ALL), +#endif +#ifdef HAVE_GIGE_API + DECLARE_BACKEND(CAP_GIGANETIX, "GIGANETIX", MODE_CAPTURE_ALL), +#endif +#ifdef HAVE_ARAVIS_API + DECLARE_BACKEND(CAP_ARAVIS, "ARAVIS", MODE_CAPTURE_ALL), +#endif +#ifdef HAVE_UNICAP + DECLARE_BACKEND(CAP_UNICAP, "UNICAP", MODE_CAPTURE_BY_FILENAME), +#endif + +#ifdef HAVE_GPHOTO2 + DECLARE_BACKEND(CAP_GPHOTO2, "GPHOTO2", MODE_CAPTURE_ALL), +#endif +#ifdef HAVE_XINE + DECLARE_BACKEND(CAP_XINE, "XINE", MODE_CAPTURE_BY_FILENAME), +#endif + + // dropped backends: MIL, TYZX, Android +}; + +bool sortByPriority(const VideoBackendInfo &lhs, const VideoBackendInfo &rhs) +{ + return lhs.priority > rhs.priority; +} + +/** @brief Manages list of enabled backends + */ +class VideoBackendRegistry +{ +protected: + std::vector enabledBackends; + VideoBackendRegistry() + { + const int N = sizeof(builtin_backends)/sizeof(builtin_backends[0]); + enabledBackends.assign(builtin_backends, builtin_backends + N); + for (int i = 0; i < N; i++) + { + VideoBackendInfo& info = enabledBackends[i]; + info.priority = 1000 - i * 10; + } + CV_LOG_DEBUG(NULL, "VIDEOIO: Builtin backends(" << N << "): " << dumpBackends()); + if (readPrioritySettings()) + { + CV_LOG_INFO(NULL, "VIDEOIO: Updated backends priorities: " << dumpBackends()); + } + int enabled = 0; + for (int i = 0; i < N; i++) + { + VideoBackendInfo& info = enabledBackends[enabled]; + if (enabled != i) + info = enabledBackends[i]; + size_t param_priority = utils::getConfigurationParameterSizeT(cv::format("OPENCV_VIDEOIO_PRIORITY_%s", info.name).c_str(), (size_t)info.priority); + CV_Assert(param_priority == (size_t)(int)param_priority); // overflow check + if (param_priority > 0) + { + info.priority = (int)param_priority; + enabled++; + } + else + { + CV_LOG_INFO(NULL, "VIDEOIO: Disable backend: " << info.name); + } + } + enabledBackends.resize(enabled); + CV_LOG_DEBUG(NULL, "VIDEOIO: Available backends(" << enabled << "): " << dumpBackends()); + std::sort(enabledBackends.begin(), enabledBackends.end(), sortByPriority); + CV_LOG_INFO(NULL, "VIDEOIO: Enabled backends(" << enabled << ", sorted by priority): " << dumpBackends()); + } + + static std::vector tokenize_string(const std::string& input, char token) + { + std::vector result; + std::string::size_type prev_pos = 0, pos = 0; + while((pos = input.find(token, pos)) != std::string::npos) + { + result.push_back(input.substr(prev_pos, pos-prev_pos)); + prev_pos = ++pos; + } + result.push_back(input.substr(prev_pos)); + return result; + } + bool readPrioritySettings() + { + bool hasChanges = false; + cv::String prioritized_backends = utils::getConfigurationParameterString("OPENCV_VIDEOIO_PRIORITY_LIST", NULL); + if (prioritized_backends.empty()) + return hasChanges; + CV_LOG_INFO(NULL, "VIDEOIO: Configured priority list (OPENCV_VIDEOIO_PRIORITY_LIST): " << prioritized_backends); + const std::vector names = tokenize_string(prioritized_backends, ','); + for (size_t i = 0; i < names.size(); i++) + { + const std::string& name = names[i]; + bool found = false; + for (size_t k = 0; k < enabledBackends.size(); k++) + { + VideoBackendInfo& info = enabledBackends[k]; + if (name == info.name) + { + info.priority = (int)(100000 + (names.size() - i) * 1000); + CV_LOG_DEBUG(NULL, "VIDEOIO: New backend priority: '" << name << "' => " << info.priority); + found = true; + hasChanges = true; + break; + } + } + if (!found) + { + CV_LOG_WARNING(NULL, "VIDEOIO: Can't prioritize unknown/unavailable backend: '" << name << "'"); + } + } + return hasChanges; + } +public: + std::string dumpBackends() const + { + std::ostringstream os; + for (size_t i = 0; i < enabledBackends.size(); i++) + { + if (i > 0) os << "; "; + const VideoBackendInfo& info = enabledBackends[i]; + os << info.name << '(' << info.priority << ')'; + } + return os.str(); + } + + static VideoBackendRegistry& getInstance() + { + static VideoBackendRegistry g_instance; + return g_instance; + } + + inline std::vector getAvailableBackends_CaptureByIndex() const + { + std::vector result; + for (size_t i = 0; i < enabledBackends.size(); i++) + { + const VideoBackendInfo& info = enabledBackends[i]; + if (info.mode & MODE_CAPTURE_BY_INDEX) + result.push_back(info); + } + return result; + } + inline std::vector getAvailableBackends_CaptureByFilename() const + { + std::vector result; + for (size_t i = 0; i < enabledBackends.size(); i++) + { + const VideoBackendInfo& info = enabledBackends[i]; + if (info.mode & MODE_CAPTURE_BY_FILENAME) + result.push_back(info); + } + return result; + } + inline std::vector getAvailableBackends_Writer() const + { + std::vector result; + for (size_t i = 0; i < enabledBackends.size(); i++) + { + const VideoBackendInfo& info = enabledBackends[i]; + if (info.mode & MODE_WRITER) + result.push_back(info); + } + return result; + } +}; + +} // namespace + +namespace videoio_registry { + +std::vector getAvailableBackends_CaptureByIndex() +{ + const std::vector result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename(); + return result; +} +std::vector getAvailableBackends_CaptureByFilename() +{ + const std::vector result = VideoBackendRegistry::getInstance().getAvailableBackends_CaptureByFilename(); + return result; +} +std::vector getAvailableBackends_Writer() +{ + const std::vector result = VideoBackendRegistry::getInstance().getAvailableBackends_Writer(); + return result; +} + +} // namespace registry + +#define TRY_OPEN(backend_func) \ +{ \ + try { \ + if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \ + CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \ + icap = backend_func; \ + if (param_VIDEOIO_DEBUG ||param_VIDEOCAPTURE_DEBUG) \ + CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p isOpened=%d ...\n", \ + #backend_func, icap.empty() ? NULL : icap.get(), icap.empty() ? -1: icap->isOpened())); \ + } catch(const cv::Exception& e) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \ + } catch (const std::exception& e) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \ + } catch(...) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \ + } \ + break; \ +} + +#define TRY_OPEN_LEGACY(backend_func) \ +{ \ + try { \ + if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \ + CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \ + capture = backend_func; \ + if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \ + CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p ...\n", #backend_func, capture)); \ + } catch(const cv::Exception& e) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \ + } catch (const std::exception& e) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \ + } catch(...) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \ + } \ + break; \ +} + + +void VideoCapture_create(CvCapture*& capture, Ptr& icap, VideoCaptureAPIs api, int index) +{ + CV_UNUSED(capture); CV_UNUSED(icap); + switch (api) + { + default: + CV_LOG_WARNING(NULL, "VideoCapture(index=" << index << ") was built without support of requested backendID=" << (int)api); + break; +#ifdef HAVE_GSTREAMER + case CAP_GSTREAMER: + TRY_OPEN(createGStreamerCapture(index)); + break; +#endif +#ifdef HAVE_MSMF + case CAP_MSMF: + TRY_OPEN(cvCreateCapture_MSMF(index)); + break; +#endif +#ifdef HAVE_DSHOW + case CAP_DSHOW: + TRY_OPEN(makePtr(index)); + break; +#endif +#ifdef HAVE_INTELPERC + case CAP_INTELPERC: + TRY_OPEN(makePtr()); + break; +#endif +#ifdef WINRT_VIDEO + case CAP_WINRT: + TRY_OPEN(makePtr(index)); + break; +#endif +#ifdef HAVE_GPHOTO2 + case CAP_GPHOTO2: + TRY_OPEN(createGPhoto2Capture(index)); + break; +#endif + case CAP_VFW: // or CAP_V4L or CAP_V4L2 +#ifdef HAVE_VFW + TRY_OPEN_LEGACY(cvCreateCameraCapture_VFW(index)) +#endif +#if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO + TRY_OPEN_LEGACY(cvCreateCameraCapture_V4L(index)) +#endif + break; + case CAP_FIREWIRE: +#ifdef HAVE_DC1394_2 + TRY_OPEN_LEGACY(cvCreateCameraCapture_DC1394_2(index)) +#endif +#ifdef HAVE_DC1394 + TRY_OPEN_LEGACY(cvCreateCameraCapture_DC1394(index)) +#endif +#ifdef HAVE_CMU1394 + TRY_OPEN_LEGACY(cvCreateCameraCapture_CMU(index)) +#endif + break; // CAP_FIREWIRE +#ifdef HAVE_MIL + case CAP_MIL: + TRY_OPEN_LEGACY(cvCreateCameraCapture_MIL(index)) + break; +#endif +#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) + case CAP_QT: + TRY_OPEN_LEGACY(cvCreateCameraCapture_QT(index)) + break; +#endif +#ifdef HAVE_UNICAP + case CAP_UNICAP: + TRY_OPEN_LEGACY(cvCreateCameraCapture_Unicap(index)) + break; +#endif +#ifdef HAVE_PVAPI + case CAP_PVAPI: + TRY_OPEN_LEGACY(cvCreateCameraCapture_PvAPI(index)) + break; +#endif +#ifdef HAVE_OPENNI + case CAP_OPENNI: + TRY_OPEN_LEGACY(cvCreateCameraCapture_OpenNI(index)) + break; +#endif +#ifdef HAVE_OPENNI2 + case CAP_OPENNI2: + TRY_OPEN_LEGACY(cvCreateCameraCapture_OpenNI2(index)) + break; +#endif +#ifdef HAVE_XIMEA + case CAP_XIAPI: + TRY_OPEN_LEGACY(cvCreateCameraCapture_XIMEA(index)) + break; +#endif + +#ifdef HAVE_AVFOUNDATION + case CAP_AVFOUNDATION: + TRY_OPEN_LEGACY(cvCreateCameraCapture_AVFoundation(index)) + break; +#endif + +#ifdef HAVE_GIGE_API + case CAP_GIGANETIX: + TRY_OPEN_LEGACY(cvCreateCameraCapture_Giganetix(index)) + break; +#endif + +#ifdef HAVE_ARAVIS_API + case CAP_ARAVIS: + TRY_OPEN_LEGACY(cvCreateCameraCapture_Aravis(index)) + break; +#endif + } // switch (api) +} + +void VideoCapture_create(CvCapture*& capture, Ptr& icap, VideoCaptureAPIs api, const cv::String& filename) +{ + switch (api) + { + default: + CV_LOG_WARNING(NULL, "VideoCapture(filename=" << filename << ") was built without support of requested backendID=" << (int)api); + break; +#if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO + case CAP_V4L: + TRY_OPEN_LEGACY(cvCreateCameraCapture_V4L(filename.c_str())) + break; +#endif + +#ifdef HAVE_VFW + case CAP_VFW: + TRY_OPEN_LEGACY(cvCreateFileCapture_VFW(filename.c_str())) + break; +#endif + +#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) + case CAP_QT: + TRY_OPEN_LEGACY(cvCreateFileCapture_QT(filename.c_str())) + break; +#endif + +#ifdef HAVE_AVFOUNDATION + case CAP_AVFOUNDATION: + TRY_OPEN_LEGACY(cvCreateFileCapture_AVFoundation(filename.c_str())) + break; +#endif + +#ifdef HAVE_OPENNI + case CAP_OPENNI: + TRY_OPEN_LEGACY(cvCreateFileCapture_OpenNI(filename.c_str())) + break; +#endif + +#ifdef HAVE_OPENNI2 + case CAP_OPENNI2: + TRY_OPEN_LEGACY(cvCreateFileCapture_OpenNI2(filename.c_str())) + break; +#endif +#ifdef HAVE_XIMEA + case CAP_XIAPI: + TRY_OPEN_LEGACY(cvCreateCameraCapture_XIMEA(filename.c_str())) + break; +#endif + case CAP_IMAGES: + TRY_OPEN_LEGACY(cvCreateFileCapture_Images(filename.c_str())) + break; +#ifdef HAVE_FFMPEG + case CAP_FFMPEG: + TRY_OPEN(cvCreateFileCapture_FFMPEG_proxy(filename)) + break; +#endif +#ifdef HAVE_GSTREAMER + case CAP_GSTREAMER: + TRY_OPEN(createGStreamerCapture(filename)) + break; +#endif +#ifdef HAVE_XINE + case CAP_XINE: + TRY_OPEN(createXINECapture(filename.c_str())) + break; +#endif +#ifdef HAVE_MSMF + case CAP_MSMF: + TRY_OPEN(cvCreateCapture_MSMF(filename)) + break; +#endif +#ifdef HAVE_GPHOTO2 + case CAP_GPHOTO2: + TRY_OPEN(createGPhoto2Capture(filename)) + break; +#endif +#ifdef HAVE_MFX + case CAP_INTEL_MFX: + TRY_OPEN(makePtr(filename)) + break; +#endif + case CAP_OPENCV_MJPEG: + TRY_OPEN(createMotionJpegCapture(filename)) + break; + } // switch +} + + +void VideoWriter_create(CvVideoWriter*& writer, Ptr& iwriter, VideoCaptureAPIs api, + const String& filename, int fourcc, double fps, const Size& frameSize, bool isColor) +{ +#define CREATE_WRITER(backend_func) \ +{ \ + try { \ + if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \ + CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \ + iwriter = backend_func; \ + if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \ + CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p isOpened=%d...\n", #backend_func, iwriter.empty() ? NULL : iwriter.get(), iwriter.empty() ? iwriter->isOpened() : -1)); \ + } catch(const cv::Exception& e) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \ + } catch (const std::exception& e) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \ + } catch(...) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \ + } \ + break; \ +} + +#define CREATE_WRITER_LEGACY(backend_func) \ +{ \ + try { \ + if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \ + CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): trying ...\n", #backend_func)); \ + writer = backend_func; \ + if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \ + CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): result=%p...\n", #backend_func, writer)); \ + } catch(const cv::Exception& e) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what())); \ + } catch (const std::exception& e) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what())); \ + } catch(...) { \ + CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func)); \ + } \ + break; \ +} + + switch (api) + { + default: + CV_LOG_ERROR(NULL, "Unknown VideoWriter backend (check getBuildInformation()): " << (int)api); + break; +#ifdef HAVE_FFMPEG + case CAP_FFMPEG: + CREATE_WRITER(cvCreateVideoWriter_FFMPEG_proxy(filename, fourcc, fps, frameSize, isColor)); + break; +#endif +#ifdef HAVE_MSMF + case CAP_MSMF: + CREATE_WRITER(cvCreateVideoWriter_MSMF(filename, fourcc, fps, frameSize, isColor)); + break; +#endif +#ifdef HAVE_MFX + case CAP_INTEL_MFX: + CREATE_WRITER(VideoWriter_IntelMFX::create(filename, fourcc, fps, frameSize, isColor)); + break; +#endif +#ifdef HAVE_VFW + case CAP_VFW: + CREATE_WRITER_LEGACY(cvCreateVideoWriter_VFW(filename.c_str(), fourcc, fps, frameSize, isColor)) + break; +#endif +#ifdef HAVE_AVFOUNDATION + case CAP_AVFOUNDATION: + CREATE_WRITER_LEGACY(cvCreateVideoWriter_AVFoundation(filename.c_str(), fourcc, fps, frameSize, isColor)) + break; +#endif +#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) + case(CAP_QT): + CREATE_WRITER_LEGACY(cvCreateVideoWriter_QT(filename.c_str(), fourcc, fps, frameSize, isColor)) + break; +#endif +#ifdef HAVE_GSTREAMER +case CAP_GSTREAMER: + CREATE_WRITER_LEGACY(cvCreateVideoWriter_GStreamer (filename.c_str(), fourcc, fps, frameSize, isColor)) + break; +#endif + case CAP_OPENCV_MJPEG: + CREATE_WRITER(createMotionJpegWriter(filename, fourcc, fps, frameSize, isColor)); + break; + case CAP_IMAGES: + if(!fourcc || !fps) + { + CREATE_WRITER_LEGACY(cvCreateVideoWriter_Images(filename.c_str())); + } + break; + } // switch(api) +} + + +} // namespace diff --git a/modules/videoio/src/videoio_registry.hpp b/modules/videoio/src/videoio_registry.hpp new file mode 100644 index 0000000000..a6d4755bd2 --- /dev/null +++ b/modules/videoio/src/videoio_registry.hpp @@ -0,0 +1,43 @@ +// 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_VIDEOIO_REGISTRY_HPP__ +#define __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__ + +namespace cv +{ + +/** Capabilities bitmask */ +enum BackendMode { + MODE_CAPTURE_BY_INDEX = 1 << 0, //!< device index + MODE_CAPTURE_BY_FILENAME = 1 << 1, //!< filename or device path (v4l2) + MODE_WRITER = 1 << 4, //!< writer + + MODE_CAPTURE_ALL = MODE_CAPTURE_BY_INDEX + MODE_CAPTURE_BY_FILENAME, +}; + +struct VideoBackendInfo { + VideoCaptureAPIs id; + BackendMode mode; + int priority; // 1000- - default builtin priority + // 0 - disabled (OPENCV_VIDEOIO_PRIORITY_ = 0) + // >10000 - prioritized list (OPENCV_VIDEOIO_PRIORITY_LIST) + const char* name; +}; + +namespace videoio_registry { + +std::vector getAvailableBackends_CaptureByIndex(); +std::vector getAvailableBackends_CaptureByFilename(); +std::vector getAvailableBackends_Writer(); + +} // namespace + +void VideoCapture_create(CvCapture*& capture, Ptr& icap, VideoCaptureAPIs api, int index); +void VideoCapture_create(CvCapture*& capture, Ptr& icap, VideoCaptureAPIs api, const cv::String& filename); +void VideoWriter_create(CvVideoWriter*& writer, Ptr& iwriter, VideoCaptureAPIs api, + const String& filename, int fourcc, double fps, const Size& frameSize, bool isColor); + +} // namespace +#endif // __OPENCV_VIDEOIO_VIDEOIO_REGISTRY_HPP__ diff --git a/modules/videoio/test/test_ffmpeg.cpp b/modules/videoio/test/test_ffmpeg.cpp index 2baeeb8b41..07bb0b7391 100644 --- a/modules/videoio/test/test_ffmpeg.cpp +++ b/modules/videoio/test/test_ffmpeg.cpp @@ -228,7 +228,7 @@ public: static std::string TmpDirectory; CreateVideoWriterInvoker(std::vector& _writers, std::vector& _files) : - ParallelLoopBody(), writers(&_writers), files(&_files) + writers(_writers), files(_files) { } @@ -240,16 +240,16 @@ public: stream << i << ".avi"; std::string fileName = tempfile(stream.str().c_str()); - files->operator[](i) = fileName; - writers->operator[](i) = new VideoWriter(fileName, CAP_FFMPEG, VideoWriter::fourcc('X','V','I','D'), 25.0f, FrameSize); + files[i] = fileName; + writers[i] = new VideoWriter(fileName, CAP_FFMPEG, VideoWriter::fourcc('X','V','I','D'), 25.0f, FrameSize); - CV_Assert(writers->operator[](i)->isOpened()); + CV_Assert(writers[i]->isOpened()); } } private: - std::vector* writers; - std::vector* files; + std::vector& writers; + std::vector& files; }; std::string CreateVideoWriterInvoker::TmpDirectory;