From 15bb0b86ce3fa7cffd3f104ecdffb15c5f91849b Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Tue, 12 Jun 2018 15:21:33 +0200 Subject: [PATCH] VideoCapture: add exception error mode similar to fstream + test --- modules/videoio/include/opencv2/videoio.hpp | 9 +++++ modules/videoio/src/cap.cpp | 38 +++++++++++++++++---- modules/videoio/test/test_video_io.cpp | 19 +++++++++++ 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp index d31985b56b..17431dd91b 100644 --- a/modules/videoio/include/opencv2/videoio.hpp +++ b/modules/videoio/include/opencv2/videoio.hpp @@ -782,9 +782,18 @@ public: */ CV_WRAP String getBackendName() const; + /** Switches exceptions mode + * + * methods raise exceptions if not successful instead of returning an error code + */ + CV_WRAP void setExceptionMode(bool enable) { throwOnFail = enable; } + + /// query if exception mode is active + CV_WRAP bool getExceptionMode() { return throwOnFail; } protected: Ptr cap; Ptr icap; + bool throwOnFail; }; class IVideoWriter; diff --git a/modules/videoio/src/cap.cpp b/modules/videoio/src/cap.cpp index 36ed6b9b76..2042d45c41 100644 --- a/modules/videoio/src/cap.cpp +++ b/modules/videoio/src/cap.cpp @@ -55,16 +55,16 @@ void DefaultDeleter::operator ()(CvCapture* obj) const { cvReleaseCap void DefaultDeleter::operator ()(CvVideoWriter* obj) const { cvReleaseVideoWriter(&obj); } -VideoCapture::VideoCapture() +VideoCapture::VideoCapture() : throwOnFail(false) {} -VideoCapture::VideoCapture(const String& filename, int apiPreference) +VideoCapture::VideoCapture(const String& filename, int apiPreference) : throwOnFail(false) { CV_TRACE_FUNCTION(); open(filename, apiPreference); } -VideoCapture::VideoCapture(int index, int apiPreference) +VideoCapture::VideoCapture(int index, int apiPreference) : throwOnFail(false) { CV_TRACE_FUNCTION(); open(index, apiPreference); @@ -112,10 +112,13 @@ bool VideoCapture::open(const String& filename, int apiPreference) CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): can't create capture", info.name)); } } catch(const cv::Exception& e) { + if(throwOnFail && apiPreference != CAP_ANY) throw; CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", info.name, e.what())); } catch (const std::exception& e) { + if(throwOnFail && apiPreference != CAP_ANY) throw; CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", info.name, e.what())); } catch(...) { + if(throwOnFail && apiPreference != CAP_ANY) throw; CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", info.name)); } } @@ -126,6 +129,10 @@ bool VideoCapture::open(const String& filename, int apiPreference) } } } + + if (throwOnFail) + CV_Error_(Error::StsError, ("could not open '%s'", filename.c_str())); + return false; } @@ -176,10 +183,13 @@ bool VideoCapture::open(int cameraNum, int apiPreference) CV_LOG_WARNING(NULL, cv::format("VIDEOIO(%s): can't create capture", info.name)); } } catch(const cv::Exception& e) { + if(throwOnFail && apiPreference != CAP_ANY) throw; CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", info.name, e.what())); } catch (const std::exception& e) { + if(throwOnFail && apiPreference != CAP_ANY) throw; CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n", info.name, e.what())); } catch(...) { + if(throwOnFail && apiPreference != CAP_ANY) throw; CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n", info.name)); } } @@ -190,6 +200,10 @@ bool VideoCapture::open(int cameraNum, int apiPreference) } } } + + if(throwOnFail) + CV_Error_(Error::StsError, ("could not open camera %d", cameraNum)); + return false; } @@ -216,15 +230,22 @@ void VideoCapture::release() bool VideoCapture::grab() { CV_INSTRUMENT_REGION(); - return !icap.empty() ? icap->grabFrame() : false; + bool ret = !icap.empty() ? icap->grabFrame() : false; + if (!ret && throwOnFail) + CV_Error(Error::StsError, ""); + return ret; } bool VideoCapture::retrieve(OutputArray image, int channel) { CV_INSTRUMENT_REGION(); + + bool ret = false; if (!icap.empty()) - return icap->retrieveFrame(channel, image); - return false; + ret = icap->retrieveFrame(channel, image); + if (!ret && throwOnFail) + CV_Error_(Error::StsError, ("could not retrieve channel %d", channel)); + return ret; } bool VideoCapture::read(OutputArray image) @@ -277,7 +298,10 @@ VideoCapture& VideoCapture::operator >> (UMat& image) bool VideoCapture::set(int propId, double value) { CV_CheckNE(propId, (int)CAP_PROP_BACKEND, "Can't set read-only property"); - return !icap.empty() ? icap->setProperty(propId, value) : false; + bool ret = !icap.empty() ? icap->setProperty(propId, value) : false; + if (!ret && throwOnFail) + CV_Error_(Error::StsError, ("could not set prop %d = %f", propId, value)); + return ret; } double VideoCapture::get(int propId) const diff --git a/modules/videoio/test/test_video_io.cpp b/modules/videoio/test/test_video_io.cpp index faf7842cff..19caa349f7 100644 --- a/modules/videoio/test/test_video_io.cpp +++ b/modules/videoio/test/test_video_io.cpp @@ -416,4 +416,23 @@ INSTANTIATE_TEST_CASE_P(videoio, videoio_synthetic, testing::ValuesIn(all_sizes), testing::ValuesIn(synthetic_params))); +TEST(Videoio, exceptions) +{ + VideoCapture cap; + + Mat mat; + + EXPECT_FALSE(cap.grab()); + EXPECT_FALSE(cap.retrieve(mat)); + EXPECT_FALSE(cap.set(CAP_PROP_POS_FRAMES, 1)); + EXPECT_FALSE(cap.open("this_does_not_exist.avi", CAP_OPENCV_MJPEG)); + + cap.setExceptionMode(true); + + EXPECT_THROW(cap.grab(), Exception); + EXPECT_THROW(cap.retrieve(mat), Exception); + EXPECT_THROW(cap.set(CAP_PROP_POS_FRAMES, 1), Exception); + EXPECT_THROW(cap.open("this_does_not_exist.avi", CAP_OPENCV_MJPEG), Exception); +} + } // namespace