diff --git a/modules/videoio/src/cap_gstreamer.cpp b/modules/videoio/src/cap_gstreamer.cpp index e24758d326..585f43959d 100644 --- a/modules/videoio/src/cap_gstreamer.cpp +++ b/modules/videoio/src/cap_gstreamer.cpp @@ -157,14 +157,14 @@ public: inline operator T* () CV_NOEXCEPT { return ptr; } inline operator /*const*/ T* () const CV_NOEXCEPT { return (T*)ptr; } // there is no const correctness in Gst C API - inline T* get() CV_NOEXCEPT { return ptr; } - inline /*const*/ T* get() const CV_NOEXCEPT { CV_Assert(ptr); return (T*)ptr; } // there is no const correctness in Gst C API + T* get() { CV_Assert(ptr); return ptr; } + /*const*/ T* get() const { CV_Assert(ptr); return (T*)ptr; } // there is no const correctness in Gst C API - inline const T* operator -> () const { CV_Assert(ptr); return ptr; } + const T* operator -> () const { CV_Assert(ptr); return ptr; } inline operator bool () const CV_NOEXCEPT { return ptr != NULL; } inline bool operator ! () const CV_NOEXCEPT { return ptr == NULL; } - inline T** getRef() { CV_Assert(ptr == NULL); return &ptr; } + T** getRef() { CV_Assert(ptr == NULL); return &ptr; } inline GSafePtr& reset(T* p) CV_NOEXCEPT // pass result of functions with "transfer floating" ownership { @@ -1313,7 +1313,21 @@ public: num_frames(0), framerate(0) { } - virtual ~CvVideoWriter_GStreamer() CV_OVERRIDE { close(); } + virtual ~CvVideoWriter_GStreamer() CV_OVERRIDE + { + try + { + close(); + } + catch (const std::exception& e) + { + CV_WARN("C++ exception in writer destructor: " << e.what()); + } + catch (...) + { + CV_WARN("Unknown exception in writer destructor. Ignore"); + } + } int getCaptureDomain() const CV_OVERRIDE { return cv::CAP_GSTREAMER; } @@ -1345,7 +1359,11 @@ void CvVideoWriter_GStreamer::close_() { handleMessage(pipeline); - if (gst_app_src_end_of_stream(GST_APP_SRC(source.get())) != GST_FLOW_OK) + if (!(bool)source) + { + CV_WARN("No source in GStreamer pipeline. Ignore"); + } + else if (gst_app_src_end_of_stream(GST_APP_SRC(source.get())) != GST_FLOW_OK) { CV_WARN("Cannot send EOS to GStreamer pipeline"); } diff --git a/modules/videoio/test/test_video_io.cpp b/modules/videoio/test/test_video_io.cpp index 913418db64..0ac93c7f24 100644 --- a/modules/videoio/test/test_video_io.cpp +++ b/modules/videoio/test/test_video_io.cpp @@ -527,4 +527,62 @@ static vector generate_Ext_Fourcc_API() INSTANTIATE_TEST_CASE_P(videoio, Videoio_Writer, testing::ValuesIn(generate_Ext_Fourcc_API())); +typedef Videoio_Writer Videoio_Writer_bad_fourcc; + +TEST_P(Videoio_Writer_bad_fourcc, nocrash) +{ + if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends())) + throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref)); + + VideoWriter writer; + EXPECT_NO_THROW(writer.open(video_file, apiPref, fourcc, fps, frame_size, true)); + ASSERT_FALSE(writer.isOpened()); + EXPECT_NO_THROW(writer.release()); +} + +static vector generate_Ext_Fourcc_API_nocrash() +{ + static const Ext_Fourcc_API params[] = { +#ifdef HAVE_MSMF_DISABLED // MSMF opens writer stream + {"wmv", "aaaa", CAP_MSMF}, + {"mov", "aaaa", CAP_MSMF}, +#endif + +#ifdef HAVE_QUICKTIME + {"mov", "aaaa", CAP_QT}, + {"avi", "aaaa", CAP_QT}, + {"mkv", "aaaa", CAP_QT}, +#endif + +#ifdef HAVE_AVFOUNDATION + {"mov", "aaaa", CAP_AVFOUNDATION}, + {"mp4", "aaaa", CAP_AVFOUNDATION}, + {"m4v", "aaaa", CAP_AVFOUNDATION}, +#endif + +#ifdef HAVE_FFMPEG + {"avi", "aaaa", CAP_FFMPEG}, + {"mkv", "aaaa", CAP_FFMPEG}, +#endif + +#ifdef HAVE_GSTREAMER + {"avi", "aaaa", CAP_GSTREAMER}, + {"mkv", "aaaa", CAP_GSTREAMER}, +#endif + {"avi", "aaaa", CAP_OPENCV_MJPEG}, +}; + + const size_t N = sizeof(params)/sizeof(params[0]); + vector result; result.reserve(N); + for (size_t i = 0; i < N; i++) + { + const Ext_Fourcc_API& src = params[i]; + Ext_Fourcc_API e = { src.ext, src.fourcc, src.api }; + result.push_back(e); + } + return result; +} + +INSTANTIATE_TEST_CASE_P(videoio, Videoio_Writer_bad_fourcc, testing::ValuesIn(generate_Ext_Fourcc_API_nocrash())); + } // namespace