From 41d8c4d8790ac46bffec1206daccf5d61fefc0ab Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Tue, 12 May 2015 17:43:28 +0200 Subject: [PATCH 1/3] allow specifying apiPreference in VideoCapture when opening a file. Add a separate function instead of an overload not to change the ABI. rename VideoCapture paramter 'device' to 'index' in CPP to reflect that it allows specifying the API. update comments to explain how to specify the API. --- modules/videoio/include/opencv2/videoio.hpp | 37 ++++++-- .../include/opencv2/videoio/videoio_c.h | 9 +- modules/videoio/src/cap.cpp | 90 +++++++++++-------- 3 files changed, 92 insertions(+), 44 deletions(-) diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp index 6daccc543..f37a8036c 100644 --- a/modules/videoio/include/opencv2/videoio.hpp +++ b/modules/videoio/include/opencv2/videoio.hpp @@ -90,7 +90,10 @@ enum { CAP_ANY = 0, // autodetect CAP_INTELPERC = 1500, // Intel Perceptual Computing SDK CAP_OPENNI2 = 1600, // OpenNI2 (for Kinect) CAP_OPENNI2_ASUS = 1610, // OpenNI2 (for Asus Xtion and Occipital Structure sensors) - CAP_GPHOTO2 = 1700 // gPhoto2 connection + CAP_GPHOTO2 = 1700, // gPhoto2 connection + CAP_GSTREAMER = 1800, // GStreamer + CAP_FFMPEG = 1900, // FFMPEG + CAP_IMAGES = 2000 // OpenCV Image Sequence (e.g. img_%02d.jpg) }; // generic properties (based on DC1394 properties) @@ -398,10 +401,19 @@ public: CV_WRAP VideoCapture(const String& filename); /** @overload - @param device id of the opened video capturing device (i.e. a camera index). If there is a single - camera connected, just pass 0. + @param filename name of the opened video file (eg. video.avi) or image sequence (eg. + img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...) + + @param apiPreference preferred Capture API to use. Can be used to enforce a specific reader + implementation if multiple are available: e.g. CAP_FFMPEG or CAP_IMAGES */ - CV_WRAP VideoCapture(int device); + CV_WRAP VideoCapture(const String& filename, int apiPreference); + + /** @overload + @param index = camera_id + domain_offset (CAP_*). id of the video capturing device to open. If there is a single + camera connected, just pass 0. Advanced Usage: to open Camera 1 using the MS Media Foundation API: index = 1 + CAP_MSMF + */ + CV_WRAP VideoCapture(int index); virtual ~VideoCapture(); @@ -415,9 +427,10 @@ public: CV_WRAP virtual bool open(const String& filename); /** @overload - @param device id of the opened video capturing device (i.e. a camera index). + @param index = camera_id + domain_offset (CAP_*). id of the video capturing device to open. If there is a single + camera connected, just pass 0. Advanced Usage: to open Camera 1 using the MS Media Foundation API: index = 1 + CAP_MSMF */ - CV_WRAP virtual bool open(int device); + CV_WRAP virtual bool open(int index); /** @brief Returns true if video capturing has been initialized already. @@ -541,6 +554,18 @@ public: */ CV_WRAP virtual double get(int propId) const; + /** @overload + + @param filename name of the opened video file (eg. video.avi) or image sequence (eg. + img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...) + + @param apiPreference preferred Capture API to use. Can be used to enforce a specific reader + implementation if multiple are available: e.g. CAP_FFMPEG or CAP_IMAGES + + The methods first call VideoCapture::release to close the already opened file or camera. + */ + CV_WRAP virtual bool open(const String& filename, int apiPreference); + protected: Ptr cap; Ptr icap; diff --git a/modules/videoio/include/opencv2/videoio/videoio_c.h b/modules/videoio/include/opencv2/videoio/videoio_c.h index b8973850c..0365b9223 100644 --- a/modules/videoio/include/opencv2/videoio/videoio_c.h +++ b/modules/videoio/include/opencv2/videoio/videoio_c.h @@ -63,6 +63,9 @@ typedef struct CvCapture CvCapture; /* start capturing frames from video file */ CVAPI(CvCapture*) cvCreateFileCapture( const char* filename ); +/* start capturing frames from video file. allows specifying a preferred API to use */ +CVAPI(CvCapture*) cvCreateFileCaptureWithPreference( const char* filename , int apiPreference); + enum { CV_CAP_ANY =0, // autodetect @@ -111,8 +114,10 @@ enum CV_CAP_INTELPERC = 1500, // Intel Perceptual Computing CV_CAP_OPENNI2 = 1600, // OpenNI2 (for Kinect) - - CV_CAP_GPHOTO2 = 1700 + CV_CAP_GPHOTO2 = 1700, + CV_CAP_GSTREAMER = 1800, // GStreamer + CV_CAP_FFMPEG = 1900, // FFMPEG + CV_CAP_IMAGES = 2000 // OpenCV Image Sequence (e.g. img_%02d.jpg) }; /* start capturing frames from camera: index = camera_index + domain_offset (CV_CAP_*) */ diff --git a/modules/videoio/src/cap.cpp b/modules/videoio/src/cap.cpp index f2b5a4a30..c222f0edd 100644 --- a/modules/videoio/src/cap.cpp +++ b/modules/videoio/src/cap.cpp @@ -359,56 +359,64 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) * Videoreader dispatching method: it tries to find the first * API that can access a given filename. */ -CV_IMPL CvCapture * cvCreateFileCapture (const char * filename) +CV_IMPL CvCapture * cvCreateFileCaptureWithPreference (const char * filename, int apiPreference) { CvCapture * result = 0; + switch(apiPreference) { + default: + case CV_CAP_FFMPEG: #ifdef HAVE_FFMPEG - if (! result) - result = cvCreateFileCapture_FFMPEG_proxy (filename); + if (! result) + result = cvCreateFileCapture_FFMPEG_proxy (filename); #endif - + case CV_CAP_VFW: #ifdef HAVE_VFW - if (! result) - result = cvCreateFileCapture_VFW (filename); + if (! result) + result = cvCreateFileCapture_VFW (filename); #endif - + case CV_CAP_MSMF: #ifdef HAVE_MSMF - if (! result) - result = cvCreateFileCapture_MSMF (filename); + if (! result) + result = cvCreateFileCapture_MSMF (filename); #endif - #ifdef HAVE_XINE - if (! result) - result = cvCreateFileCapture_XINE (filename); + if (! result) + result = cvCreateFileCapture_XINE (filename); #endif - + case CV_CAP_GSTREAMER: #ifdef HAVE_GSTREAMER - if (! result) - result = cvCreateCapture_GStreamer (CV_CAP_GSTREAMER_FILE, filename); + if (! result) + result = cvCreateCapture_GStreamer (CV_CAP_GSTREAMER_FILE, filename); #endif - + case CV_CAP_QT: #if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) - if (! result) - result = cvCreateFileCapture_QT (filename); + if (! result) + result = cvCreateFileCapture_QT (filename); #endif - + case CV_CAP_AVFOUNDATION: #ifdef HAVE_AVFOUNDATION - if (! result) - result = cvCreateFileCapture_AVFoundation (filename); + if (! result) + result = cvCreateFileCapture_AVFoundation (filename); #endif - + case CV_CAP_OPENNI: #ifdef HAVE_OPENNI - if (! result) - result = cvCreateFileCapture_OpenNI (filename); + if (! result) + result = cvCreateFileCapture_OpenNI (filename); #endif - - if (! result) - result = cvCreateFileCapture_Images (filename); + case CV_CAP_IMAGES: + if (! result) + result = cvCreateFileCapture_Images (filename); + } return result; } +CV_IMPL CvCapture * cvCreateFileCapture (const char * filename) +{ + return cvCreateFileCaptureWithPreference(filename, CV_CAP_ANY); +} + /** * Videowriter dispatching method: it tries to find the first * API that can write a given stream. @@ -615,14 +623,19 @@ static Ptr IVideoWriter_create(const String& filename, int _fourcc VideoCapture::VideoCapture() {} -VideoCapture::VideoCapture(const String& filename) +VideoCapture::VideoCapture(const String& filename, int apiPreference) { - open(filename); + open(filename, apiPreference); } -VideoCapture::VideoCapture(int device) +VideoCapture::VideoCapture(const String& filename) { - open(device); + open(filename, CAP_ANY); +} + +VideoCapture::VideoCapture(int index) +{ + open(index); } VideoCapture::~VideoCapture() @@ -631,24 +644,29 @@ VideoCapture::~VideoCapture() cap.release(); } -bool VideoCapture::open(const String& filename) +bool VideoCapture::open(const String& filename, int apiPreference) { if (isOpened()) release(); icap = IVideoCapture_create(filename); if (!icap.empty()) return true; - cap.reset(cvCreateFileCapture(filename.c_str())); + cap.reset(cvCreateFileCaptureWithPreference(filename.c_str(), apiPreference)); return isOpened(); } -bool VideoCapture::open(int device) +bool VideoCapture::open(const String& filename) +{ + return open(filename, CAP_ANY); +} + +bool VideoCapture::open(int index) { if (isOpened()) release(); - icap = IVideoCapture_create(device); + icap = IVideoCapture_create(index); if (!icap.empty()) return true; - cap.reset(cvCreateCameraCapture(device)); + cap.reset(cvCreateCameraCapture(index)); return isOpened(); } From 2909e07cb2a090ab4ea7da91f0dab5da6b6ea7c4 Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Fri, 26 Jun 2015 12:04:56 +0200 Subject: [PATCH 2/3] deny any other interfaces if someone is specified as preference it provides more expectable results to end-users. based on feedback by Alexander Alekhin --- modules/videoio/src/cap.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/modules/videoio/src/cap.cpp b/modules/videoio/src/cap.cpp index c222f0edd..67861c333 100644 --- a/modules/videoio/src/cap.cpp +++ b/modules/videoio/src/cap.cpp @@ -365,45 +365,64 @@ CV_IMPL CvCapture * cvCreateFileCaptureWithPreference (const char * filename, in switch(apiPreference) { default: - case CV_CAP_FFMPEG: + // user specified an API we do not know + // bail out to let the user know that it is not available + if (apiPreference) break; + #ifdef HAVE_FFMPEG + case CV_CAP_FFMPEG: if (! result) result = cvCreateFileCapture_FFMPEG_proxy (filename); + if (apiPreference) break; #endif - case CV_CAP_VFW: + #ifdef HAVE_VFW + case CV_CAP_VFW: if (! result) result = cvCreateFileCapture_VFW (filename); + if (apiPreference) break; #endif + case CV_CAP_MSMF: #ifdef HAVE_MSMF if (! result) result = cvCreateFileCapture_MSMF (filename); #endif + #ifdef HAVE_XINE if (! result) result = cvCreateFileCapture_XINE (filename); #endif - case CV_CAP_GSTREAMER: + if (apiPreference) break; + #ifdef HAVE_GSTREAMER + case CV_CAP_GSTREAMER: if (! result) result = cvCreateCapture_GStreamer (CV_CAP_GSTREAMER_FILE, filename); + if (apiPreference) break; #endif - case CV_CAP_QT: + #if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) + case CV_CAP_QT: if (! result) result = cvCreateFileCapture_QT (filename); + if (apiPreference) break; #endif - case CV_CAP_AVFOUNDATION: + #ifdef HAVE_AVFOUNDATION + case CV_CAP_AVFOUNDATION: if (! result) result = cvCreateFileCapture_AVFoundation (filename); + if (apiPreference) break; #endif - case CV_CAP_OPENNI: + #ifdef HAVE_OPENNI + case CV_CAP_OPENNI: if (! result) result = cvCreateFileCapture_OpenNI (filename); + if (apiPreference) break; #endif + case CV_CAP_IMAGES: if (! result) result = cvCreateFileCapture_Images (filename); From b1842a4b8954cbc4d73d6a84bfb5d20bd697dd1e Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Fri, 26 Jun 2015 12:18:11 +0200 Subject: [PATCH 3/3] use simplified API selection logic in cvCreateCameraCapture as well --- modules/videoio/src/cap.cpp | 243 +++++++++++------------------------- 1 file changed, 74 insertions(+), 169 deletions(-) diff --git a/modules/videoio/src/cap.cpp b/modules/videoio/src/cap.cpp index 67861c333..d2da6edfe 100644 --- a/modules/videoio/src/cap.cpp +++ b/modules/videoio/src/cap.cpp @@ -126,233 +126,138 @@ CV_IMPL int cvGetCaptureDomain( CvCapture* capture) */ CV_IMPL CvCapture * cvCreateCameraCapture (int index) { - int domains[] = - { -#ifdef HAVE_MSMF - CV_CAP_MSMF, -#endif -#if 1 - CV_CAP_IEEE1394, // identical to CV_CAP_DC1394 -#endif -#ifdef HAVE_TYZX - CV_CAP_STEREO, -#endif -#ifdef HAVE_PVAPI - CV_CAP_PVAPI, -#endif -#if 1 - CV_CAP_VFW, // identical to CV_CAP_V4L -#endif -#ifdef HAVE_MIL - CV_CAP_MIL, -#endif -#if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) - CV_CAP_QT, -#endif -#ifdef HAVE_UNICAP - CV_CAP_UNICAP, -#endif -#ifdef HAVE_OPENNI - CV_CAP_OPENNI, -#endif -#ifdef HAVE_OPENNI2 - CV_CAP_OPENNI2, -#endif -#ifdef HAVE_XIMEA - CV_CAP_XIAPI, -#endif -#ifdef HAVE_AVFOUNDATION - CV_CAP_AVFOUNDATION, -#endif -#ifdef HAVE_GIGE_API - CV_CAP_GIGANETIX, -#endif -#ifdef HAVE_INTELPERC - CV_CAP_INTELPERC, -#endif - -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_MSMF) || \ - defined(HAVE_TYZX) || \ - defined(HAVE_VFW) || \ - defined(HAVE_LIBV4L) || \ - defined(HAVE_CAMV4L) || \ - defined(HAVE_CAMV4L2) || \ - defined(HAVE_VIDEOIO) || \ - defined(HAVE_GSTREAMER) || \ - defined(HAVE_DC1394_2) || \ - defined(HAVE_DC1394) || \ - defined(HAVE_CMU1394) || \ - defined(HAVE_MIL) || \ - defined(HAVE_QUICKTIME) || \ - defined(HAVE_QTKIT) || \ - defined(HAVE_UNICAP) || \ - defined(HAVE_PVAPI) || \ - defined(HAVE_OPENNI) || \ - defined(HAVE_OPENNI2) || \ - defined(HAVE_XIMEA) || \ - defined(HAVE_AVFOUNDATION) || \ - defined(HAVE_GIGE_API) || \ - defined(HAVE_INTELPERC) || \ - (0) - // local variable to memorize the captured device - CvCapture *capture; -#endif + // 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; - switch (domains[i]) - { #ifdef HAVE_MSMF - case CV_CAP_MSMF: - capture = cvCreateCameraCapture_MSMF (index); - if (capture) - return capture; - break; + case CV_CAP_MSMF: + if (!capture) + capture = cvCreateCameraCapture_MSMF(index); + if (pref) break; #endif #ifdef HAVE_TYZX - case CV_CAP_STEREO: - capture = cvCreateCameraCapture_TYZX (index); - if (capture) - return capture; - break; + case CV_CAP_STEREO: + if (!capture) + capture = cvCreateCameraCapture_TYZX(index); + if (pref) break; #endif - case CV_CAP_VFW: + case CV_CAP_VFW: #ifdef HAVE_VFW - capture = cvCreateCameraCapture_VFW (index); - if (capture) - return capture; + if (!capture) + capture = cvCreateCameraCapture_VFW(index); #endif #if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO - capture = cvCreateCameraCapture_V4L (index); - if (capture) - return capture; + if (!capture) + capture = cvCreateCameraCapture_V4L(index); #endif #ifdef HAVE_GSTREAMER + if (!capture) capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L2, 0); - if (capture) - return capture; - capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L, 0); - if (capture) - return capture; -#endif - break; //CV_CAP_VFW - case CV_CAP_FIREWIRE: + if (!capture) + capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L, 0); +#endif + if (pref) break; // CV_CAP_VFW + + case CV_CAP_FIREWIRE: #ifdef HAVE_DC1394_2 - capture = cvCreateCameraCapture_DC1394_2 (index); - if (capture) - return capture; + if (!capture) + capture = cvCreateCameraCapture_DC1394_2(index); #endif #ifdef HAVE_DC1394 - capture = cvCreateCameraCapture_DC1394 (index); - if (capture) - return capture; + if (!capture) + capture = cvCreateCameraCapture_DC1394(index); #endif #ifdef HAVE_CMU1394 - capture = cvCreateCameraCapture_CMU (index); - if (capture) - return capture; + if (!capture) + capture = cvCreateCameraCapture_CMU(index); #endif #if defined(HAVE_GSTREAMER) && 0 - //Re-enable again when gstreamer 1394 support will land in the backend code + // Re-enable again when gstreamer 1394 support will land in the backend code + if (!capture) capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_1394, 0); - if (capture) - return capture; #endif - break; //CV_CAP_FIREWIRE + if (pref) break; // CV_CAP_FIREWIRE #ifdef HAVE_MIL - case CV_CAP_MIL: - capture = cvCreateCameraCapture_MIL (index); - if (capture) - return capture; - break; + case CV_CAP_MIL: + if (!capture) + capture = cvCreateCameraCapture_MIL(index); + if (pref) break; #endif #if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT) - case CV_CAP_QT: - capture = cvCreateCameraCapture_QT (index); - if (capture) - return capture; - break; + case CV_CAP_QT: + if (!capture) + capture = cvCreateCameraCapture_QT(index); + if (pref) break; #endif #ifdef HAVE_UNICAP - case CV_CAP_UNICAP: - capture = cvCreateCameraCapture_Unicap (index); - if (capture) - return capture; - break; + case CV_CAP_UNICAP: + if (!capture) + capture = cvCreateCameraCapture_Unicap(index); + if (pref) break; #endif #ifdef HAVE_PVAPI - case CV_CAP_PVAPI: - capture = cvCreateCameraCapture_PvAPI (index); - if (capture) - return capture; - break; + case CV_CAP_PVAPI: + if (!capture) + capture = cvCreateCameraCapture_PvAPI(index); + if (pref) break; #endif #ifdef HAVE_OPENNI - case CV_CAP_OPENNI: - capture = cvCreateCameraCapture_OpenNI (index); - if (capture) - return capture; - break; + case CV_CAP_OPENNI: + if (!capture) + capture = cvCreateCameraCapture_OpenNI(index); + if (pref) break; #endif #ifdef HAVE_OPENNI2 - case CV_CAP_OPENNI2: + case CV_CAP_OPENNI2: + if (!capture) capture = cvCreateCameraCapture_OpenNI(index); - if (capture) - return capture; - break; + if (pref) break; #endif #ifdef HAVE_XIMEA - case CV_CAP_XIAPI: - capture = cvCreateCameraCapture_XIMEA (index); - if (capture) - return capture; - break; + case CV_CAP_XIAPI: + if (!capture) + capture = cvCreateCameraCapture_XIMEA(index); + if (pref) break; #endif #ifdef HAVE_AVFOUNDATION - case CV_CAP_AVFOUNDATION: - capture = cvCreateCameraCapture_AVFoundation (index); - if (capture) - return capture; - break; + case CV_CAP_AVFOUNDATION: + if (!capture) + capture = cvCreateCameraCapture_AVFoundation(index); + if (pref) break; #endif #ifdef HAVE_GIGE_API - case CV_CAP_GIGANETIX: - capture = cvCreateCameraCapture_Giganetix (index); - if (capture) - return capture; - break; // CV_CAP_GIGANETIX + case CV_CAP_GIGANETIX: + if (!capture) + capture = cvCreateCameraCapture_Giganetix(index); + if (pref) break; // CV_CAP_GIGANETIX #endif - } } - // failed open a camera - return 0; + return capture; } /**