Merge pull request #19394 from MaximMilashchenko:params
authorMaximMilashchenko <67949029+MaximMilashchenko@users.noreply.github.com>
Wed, 27 Jan 2021 22:07:43 +0000 (01:07 +0300)
committerGitHub <noreply@github.com>
Wed, 27 Jan 2021 22:07:43 +0000 (22:07 +0000)
add video capture parameters

* add parameters

* videoio: revert unnecessary massive changes

* videoio: support capture parameters in backends API

- add tests
- FFmpeg backend sample code
- StaticBackend API is done
- support through PluginBackend API will be added later

Co-authored-by: Milashchenko <maksim.milashchenko@intel.com>
Co-authored-by: Alexander Alekhin <alexander.a.alekhin@gmail.com>
modules/videoio/include/opencv2/videoio.hpp
modules/videoio/misc/objc/gen_dict.json
modules/videoio/src/backend.hpp
modules/videoio/src/backend_plugin.cpp
modules/videoio/src/backend_static.cpp
modules/videoio/src/cap.cpp
modules/videoio/src/cap_ffmpeg.cpp
modules/videoio/src/cap_interface.hpp
modules/videoio/test/test_camera.cpp
modules/videoio/test/test_ffmpeg.cpp

index 7beb810..c8067e9 100644 (file)
@@ -652,6 +652,14 @@ public:
     CV_WRAP explicit VideoCapture(const String& filename, int apiPreference = CAP_ANY);
 
     /** @overload
+    @brief Opens a video file or a capturing device or an IP video stream for video capturing with API Preference and parameters
+
+    The `params` parameter allows to specify extra parameters encoded as pairs `(paramId_1, paramValue_1, paramId_2, paramValue_2, ...)`.
+    See cv::VideoCaptureProperties
+    */
+    CV_WRAP explicit VideoCapture(const String& filename, int apiPreference, const std::vector<int>& params);
+
+    /** @overload
     @brief  Opens a camera for video capturing
 
     @param index id of the video capturing device to open. To open default camera using default backend just pass 0.
@@ -663,6 +671,14 @@ public:
     */
     CV_WRAP explicit VideoCapture(int index, int apiPreference = CAP_ANY);
 
+    /** @overload
+    @brief Opens a camera for video capturing with API Preference and parameters
+
+    The `params` parameter allows to specify extra parameters encoded as pairs `(paramId_1, paramValue_1, paramId_2, paramValue_2, ...)`.
+    See cv::VideoCaptureProperties
+    */
+    CV_WRAP explicit VideoCapture(int index, int apiPreference, const std::vector<int>& params);
+
     /** @brief Default destructor
 
     The method first calls VideoCapture::release to close the already opened file or camera.
@@ -684,6 +700,19 @@ public:
 
     @overload
 
+    The `params` parameter allows to specify extra parameters encoded as pairs `(paramId_1, paramValue_1, paramId_2, paramValue_2, ...)`.
+    See cv::VideoCaptureProperties
+
+    @return `true` if the file has been successfully opened
+
+    The method first calls VideoCapture::release to close the already opened file or camera.
+     */
+    CV_WRAP virtual bool open(const String& filename, int apiPreference, const std::vector<int>& params);
+
+    /** @brief  Opens a camera for video capturing
+
+    @overload
+
     Parameters are same as the constructor VideoCapture(int index, int apiPreference = CAP_ANY)
     @return `true` if the camera has been successfully opened.
 
@@ -693,6 +722,19 @@ public:
 
     /** @brief Returns true if video capturing has been initialized already.
 
+    @overload
+
+    The `params` parameter allows to specify extra parameters encoded as pairs `(paramId_1, paramValue_1, paramId_2, paramValue_2, ...)`.
+    See cv::VideoCaptureProperties
+
+    @return `true` if the camera has been successfully opened.
+
+    The method first calls VideoCapture::release to close the already opened file or camera.
+    */
+    CV_WRAP virtual bool open(int index, int apiPreference, const std::vector<int>& params);
+
+    /** @brief Returns true if video capturing has been initialized already.
+
     If the previous call to VideoCapture constructor or VideoCapture::open() succeeded, the method returns
     true.
      */
index e71c9ec..70dc844 100644 (file)
@@ -13,7 +13,8 @@
     },
     "func_arg_fix" : {
         "VideoCapture" : {
-            "(BOOL)open:(int)index apiPreference:(int)apiPreference" : { "open" : {"name" : "openWithIndex"} }
+            "(BOOL)open:(int)index apiPreference:(int)apiPreference" : { "open" : {"name" : "openWithIndex"} },
+            "(BOOL)open:(int)index apiPreference:(int)apiPreference params:(IntVector*)params" : { "open" : {"name" : "openWithIndexAndParameters"} }
         }
     }
 }
index 1b2a1e6..ecf0e0d 100644 (file)
@@ -16,8 +16,8 @@ class IBackend
 {
 public:
     virtual ~IBackend() {}
-    virtual Ptr<IVideoCapture> createCapture(int camera) const = 0;
-    virtual Ptr<IVideoCapture> createCapture(const std::string &filename) const = 0;
+    virtual Ptr<IVideoCapture> createCapture(int camera, const VideoCaptureParameters& params) const = 0;
+    virtual Ptr<IVideoCapture> createCapture(const std::string &filename, const VideoCaptureParameters& params) const = 0;
     virtual Ptr<IVideoWriter> createWriter(const std::string& filename, int fourcc, double fps, const cv::Size& sz,
                                            const VideoWriterParameters& params) const = 0;
 };
@@ -33,14 +33,21 @@ public:
 
 typedef Ptr<IVideoCapture> (*FN_createCaptureFile)(const std::string & filename);
 typedef Ptr<IVideoCapture> (*FN_createCaptureCamera)(int camera);
+typedef Ptr<IVideoCapture> (*FN_createCaptureFileWithParams)(const std::string & filename, const VideoCaptureParameters& params);
+typedef Ptr<IVideoCapture> (*FN_createCaptureCameraWithParams)(int camera, const VideoCaptureParameters& params);
 typedef Ptr<IVideoWriter>  (*FN_createWriter)(const std::string& filename, int fourcc, double fps, const Size& sz,
                                               const VideoWriterParameters& params);
 Ptr<IBackendFactory> createBackendFactory(FN_createCaptureFile createCaptureFile,
                                           FN_createCaptureCamera createCaptureCamera,
                                           FN_createWriter createWriter);
+Ptr<IBackendFactory> createBackendFactory(FN_createCaptureFileWithParams createCaptureFile,
+                                          FN_createCaptureCameraWithParams createCaptureCamera,
+                                          FN_createWriter createWriter);
 
 Ptr<IBackendFactory> createPluginBackendFactory(VideoCaptureAPIs id, const char* baseName);
 
+void applyParametersFallback(const Ptr<IVideoCapture>& cap, const VideoCaptureParameters& params);
+
 } // namespace cv::
 
 #endif // BACKEND_HPP_DEFINED
index 1cdf4bd..91270d9 100644 (file)
@@ -363,8 +363,10 @@ public:
         }
     }
 
-    Ptr<IVideoCapture> createCapture(int camera) const CV_OVERRIDE;
-    Ptr<IVideoCapture> createCapture(const std::string &filename) const CV_OVERRIDE;
+    Ptr<IVideoCapture> createCapture(int camera) const;
+    Ptr<IVideoCapture> createCapture(int camera, const VideoCaptureParameters& params) const CV_OVERRIDE;
+    Ptr<IVideoCapture> createCapture(const std::string &filename) const;
+    Ptr<IVideoCapture> createCapture(const std::string &filename, const VideoCaptureParameters& params) const CV_OVERRIDE;
     Ptr<IVideoWriter> createWriter(const std::string& filename, int fourcc, double fps,
                                    const cv::Size& sz, const VideoWriterParameters& params) const CV_OVERRIDE;
 };
@@ -753,10 +755,22 @@ Ptr<IVideoCapture> PluginBackend::createCapture(int camera) const
     catch (...)
     {
         CV_LOG_DEBUG(NULL, "Video I/O: can't create camera capture: " << camera);
+        throw;
     }
     return Ptr<IVideoCapture>();
 }
 
+Ptr<IVideoCapture> PluginBackend::createCapture(int camera, const VideoCaptureParameters& params) const
+{
+    // TODO Update plugins API to support parameters
+    Ptr<IVideoCapture> cap = createCapture(camera);
+    if (cap && !params.empty())
+    {
+        applyParametersFallback(cap, params);
+    }
+    return cap;
+}
+
 Ptr<IVideoCapture> PluginBackend::createCapture(const std::string &filename) const
 {
     try
@@ -769,10 +783,22 @@ Ptr<IVideoCapture> PluginBackend::createCapture(const std::string &filename) con
     catch (...)
     {
         CV_LOG_DEBUG(NULL, "Video I/O: can't open file capture: " << filename);
+        throw;
     }
     return Ptr<IVideoCapture>();
 }
 
+Ptr<IVideoCapture> PluginBackend::createCapture(const std::string &filename, const VideoCaptureParameters& params) const
+{
+    // TODO Update plugins API to support parameters
+    Ptr<IVideoCapture> cap = createCapture(filename);
+    if (cap && !params.empty())
+    {
+        applyParametersFallback(cap, params);
+    }
+    return cap;
+}
+
 Ptr<IVideoWriter> PluginBackend::createWriter(const std::string& filename, int fourcc, double fps,
                                               const cv::Size& sz, const VideoWriterParameters& params) const
 {
index 5676286..1d23c28 100644 (file)
@@ -8,6 +8,28 @@
 
 namespace cv {
 
+
+void applyParametersFallback(const Ptr<IVideoCapture>& cap, const VideoCaptureParameters& params)
+{
+    std::vector<int> props = params.getUnused();
+    CV_LOG_INFO(NULL, "VIDEOIO: Backend '" << videoio_registry::getBackendName((VideoCaptureAPIs)cap->getCaptureDomain()) <<
+                      "' implementation doesn't support parameters in .open(). Applying " <<
+                      props.size() << " properties through .setProperty()");
+    for (int prop : props)
+    {
+        double value = params.get<double>(prop, -1);
+        CV_LOG_INFO(NULL, "VIDEOIO: apply parameter: [" << prop << "]=" <<
+                          cv::format("%g / %lld / 0x%16llx", value, (long long)value, (long long)value));
+        if (!cap->setProperty(prop, value))
+        {
+            CV_Error_(cv::Error::StsNotImplemented, ("VIDEOIO: Failed to apply invalid or unsupported parameter: [%d]=%g / %lld / 0x%08llx", prop, value, (long long)value, (long long)value));
+        }
+    }
+    // NB: there is no dedicated "commit" parameters event, implementations should commit after each property automatically
+}
+
+
+// Legacy API. Modern API with parameters is below
 class StaticBackend: public IBackend
 {
 public:
@@ -20,18 +42,33 @@ public:
     {
         // nothing
     }
+
     ~StaticBackend() CV_OVERRIDE {}
 
-    Ptr<IVideoCapture> createCapture(int camera) const CV_OVERRIDE
+    Ptr<IVideoCapture> createCapture(int camera, const VideoCaptureParameters& params) const CV_OVERRIDE
     {
         if (fn_createCaptureCamera_)
-            return fn_createCaptureCamera_(camera);
+        {
+            Ptr<IVideoCapture> cap = fn_createCaptureCamera_(camera);
+            if (cap && !params.empty())
+            {
+                applyParametersFallback(cap, params);
+            }
+            return cap;
+        }
         return Ptr<IVideoCapture>();
     }
-    Ptr<IVideoCapture> createCapture(const std::string &filename) const CV_OVERRIDE
+    Ptr<IVideoCapture> createCapture(const std::string &filename, const VideoCaptureParameters& params) const CV_OVERRIDE
     {
         if (fn_createCaptureFile_)
-            return fn_createCaptureFile_(filename);
+        {
+            Ptr<IVideoCapture> cap = fn_createCaptureFile_(filename);
+            if (cap && !params.empty())
+            {
+                applyParametersFallback(cap, params);
+            }
+            return cap;
+        }
         return Ptr<IVideoCapture>();
     }
     Ptr<IVideoWriter> createWriter(const std::string& filename, int fourcc, double fps,
@@ -63,6 +100,7 @@ public:
     }
 };
 
+
 Ptr<IBackendFactory> createBackendFactory(FN_createCaptureFile createCaptureFile,
                                           FN_createCaptureCamera createCaptureCamera,
                                           FN_createWriter createWriter)
@@ -70,4 +108,71 @@ Ptr<IBackendFactory> createBackendFactory(FN_createCaptureFile createCaptureFile
     return makePtr<StaticBackendFactory>(createCaptureFile, createCaptureCamera, createWriter).staticCast<IBackendFactory>();
 }
 
+
+
+class StaticBackendWithParams: public IBackend
+{
+public:
+    FN_createCaptureFileWithParams fn_createCaptureFile_;
+    FN_createCaptureCameraWithParams fn_createCaptureCamera_;
+    FN_createWriter fn_createWriter_;
+
+    StaticBackendWithParams(FN_createCaptureFileWithParams fn_createCaptureFile, FN_createCaptureCameraWithParams fn_createCaptureCamera, FN_createWriter fn_createWriter)
+        : fn_createCaptureFile_(fn_createCaptureFile), fn_createCaptureCamera_(fn_createCaptureCamera), fn_createWriter_(fn_createWriter)
+    {
+        // nothing
+    }
+
+    ~StaticBackendWithParams() CV_OVERRIDE {}
+
+    Ptr<IVideoCapture> createCapture(int camera, const VideoCaptureParameters& params) const CV_OVERRIDE
+    {
+        if (fn_createCaptureCamera_)
+            return fn_createCaptureCamera_(camera, params);
+        return Ptr<IVideoCapture>();
+    }
+    Ptr<IVideoCapture> createCapture(const std::string &filename, const VideoCaptureParameters& params) const CV_OVERRIDE
+    {
+        if (fn_createCaptureFile_)
+            return fn_createCaptureFile_(filename, params);
+        return Ptr<IVideoCapture>();
+    }
+    Ptr<IVideoWriter> createWriter(const std::string& filename, int fourcc, double fps,
+                                   const cv::Size& sz, const VideoWriterParameters& params) const CV_OVERRIDE
+    {
+        if (fn_createWriter_)
+            return fn_createWriter_(filename, fourcc, fps, sz, params);
+        return Ptr<IVideoWriter>();
+    }
+}; // StaticBackendWithParams
+
+class StaticBackendWithParamsFactory : public IBackendFactory
+{
+protected:
+    Ptr<StaticBackendWithParams> backend;
+
+public:
+    StaticBackendWithParamsFactory(FN_createCaptureFileWithParams createCaptureFile, FN_createCaptureCameraWithParams createCaptureCamera, FN_createWriter createWriter)
+        : backend(makePtr<StaticBackendWithParams>(createCaptureFile, createCaptureCamera, createWriter))
+    {
+        // nothing
+    }
+
+    ~StaticBackendWithParamsFactory() CV_OVERRIDE {}
+
+    Ptr<IBackend> getBackend() const CV_OVERRIDE
+    {
+        return backend.staticCast<IBackend>();
+    }
+};
+
+
+Ptr<IBackendFactory> createBackendFactory(FN_createCaptureFileWithParams createCaptureFile,
+                                          FN_createCaptureCameraWithParams createCaptureCamera,
+                                          FN_createWriter createWriter)
+{
+    return makePtr<StaticBackendWithParamsFactory>(createCaptureFile, createCaptureCamera, createWriter).staticCast<IBackendFactory>();
+}
+
+
 } // namespace
index 77a2c36..f0afc1f 100644 (file)
@@ -75,12 +75,26 @@ VideoCapture::VideoCapture(const String& filename, int apiPreference) : throwOnF
     open(filename, apiPreference);
 }
 
+VideoCapture::VideoCapture(const String& filename, int apiPreference, const std::vector<int>& params)
+    : throwOnFail(true)
+{
+    CV_TRACE_FUNCTION();
+    open(filename, apiPreference, params);
+}
+
 VideoCapture::VideoCapture(int index, int apiPreference) : throwOnFail(false)
 {
     CV_TRACE_FUNCTION();
     open(index, apiPreference);
 }
 
+VideoCapture::VideoCapture(int index, int apiPreference, const std::vector<int>& params)
+    : throwOnFail(true)
+{
+    CV_TRACE_FUNCTION();
+    open(index, apiPreference, params);
+}
+
 VideoCapture::~VideoCapture()
 {
     CV_TRACE_FUNCTION();
@@ -89,13 +103,19 @@ VideoCapture::~VideoCapture()
 
 bool VideoCapture::open(const String& filename, int apiPreference)
 {
-    CV_TRACE_FUNCTION();
+    return open(filename, apiPreference, std::vector<int>());
+}
+
+bool VideoCapture::open(const String& filename, int apiPreference, const std::vector<int>& params)
+{
+    CV_INSTRUMENT_REGION();
 
     if (isOpened())
     {
         release();
     }
 
+    const VideoCaptureParameters parameters(params);
     const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByFilename();
     for (size_t i = 0; i < backends.size(); i++)
     {
@@ -112,7 +132,7 @@ bool VideoCapture::open(const String& filename, int apiPreference)
             {
                 try
                 {
-                    icap = backend->createCapture(filename);
+                    icap = backend->createCapture(filename, parameters);
                     if (!icap.empty())
                     {
                         CV_CAPTURE_LOG_DEBUG(NULL,
@@ -182,6 +202,11 @@ bool VideoCapture::open(const String& filename, int apiPreference)
 
 bool VideoCapture::open(int cameraNum, int apiPreference)
 {
+    return open(cameraNum, apiPreference, std::vector<int>());
+}
+
+bool VideoCapture::open(int cameraNum, int apiPreference, const std::vector<int>& params)
+{
     CV_TRACE_FUNCTION();
 
     if (isOpened())
@@ -200,6 +225,7 @@ bool VideoCapture::open(int cameraNum, int apiPreference)
         }
     }
 
+    const VideoCaptureParameters parameters(params);
     const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByIndex();
     for (size_t i = 0; i < backends.size(); i++)
     {
@@ -216,7 +242,7 @@ bool VideoCapture::open(int cameraNum, int apiPreference)
             {
                 try
                 {
-                    icap = backend->createCapture(cameraNum);
+                    icap = backend->createCapture(cameraNum, parameters);
                     if (!icap.empty())
                     {
                         CV_CAPTURE_LOG_DEBUG(NULL,
index e803721..07f9998 100644 (file)
@@ -67,7 +67,11 @@ class CvCapture_FFMPEG_proxy CV_FINAL : public cv::IVideoCapture
 {
 public:
     CvCapture_FFMPEG_proxy() { ffmpegCapture = 0; }
-    CvCapture_FFMPEG_proxy(const cv::String& filename) { ffmpegCapture = 0; open(filename); }
+    CvCapture_FFMPEG_proxy(const cv::String& filename, const cv::VideoCaptureParameters& params)
+        : ffmpegCapture(NULL)
+    {
+        open(filename, params);
+    }
     virtual ~CvCapture_FFMPEG_proxy() { close(); }
 
     virtual double getProperty(int propId) const CV_OVERRIDE
@@ -104,6 +108,28 @@ public:
         ffmpegCapture = icvCreateFileCapture_FFMPEG_p( filename.c_str() );
         return ffmpegCapture != 0;
     }
+    bool open(const cv::String& filename, const cv::VideoCaptureParameters& params)
+    {
+        close();
+
+        ffmpegCapture = icvCreateFileCapture_FFMPEG_p(filename.c_str());
+        if (ffmpegCapture && !params.empty())
+        {
+            if (params.has(CAP_PROP_FORMAT))  // just a sample code
+            {
+                int value = params.get<int>(CAP_PROP_FORMAT);
+                if (!setProperty(CAP_PROP_FORMAT, value))
+                {
+                    CV_Error_(Error::StsBadArg, ("VIDEOIO/FFMPEG: CAP_PROP_FORMAT parameter value is invalid/unsupported: %d", value));
+                }
+            }
+            if (params.warnUnusedParameters())
+            {
+                CV_Error(Error::StsBadArg, "VIDEOIO/FFMPEG: unsupported parameters in .open(), see logger INFO channel for details");
+            }
+        }
+        return ffmpegCapture != 0;
+    }
     virtual void close()
     {
         if (ffmpegCapture)
@@ -145,9 +171,9 @@ protected:
 
 } // namespace
 
-cv::Ptr<cv::IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const std::string &filename)
+cv::Ptr<cv::IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const std::string &filename, const cv::VideoCaptureParameters& params)
 {
-    cv::Ptr<CvCapture_FFMPEG_proxy> capture = cv::makePtr<CvCapture_FFMPEG_proxy>(filename);
+    cv::Ptr<CvCapture_FFMPEG_proxy> capture = cv::makePtr<CvCapture_FFMPEG_proxy>(filename, params);
     if (capture && capture->isOpened())
         return capture;
     return cv::Ptr<cv::IVideoCapture>();
@@ -246,7 +272,7 @@ CvResult CV_API_CALL cv_capture_open(const char* filename, int camera_index, CV_
     CvCapture_FFMPEG_proxy *cap = 0;
     try
     {
-        cap = new CvCapture_FFMPEG_proxy(filename);
+        cap = new CvCapture_FFMPEG_proxy(filename, cv::VideoCaptureParameters());
         if (cap->isOpened())
         {
             *handle = (CvPluginCapture)cap;
index 720fb0b..bc80300 100644 (file)
@@ -52,22 +52,22 @@ inline bool castParameterTo(int paramValue)
 }
 }
 
-class VideoWriterParameters
+class VideoParameters
 {
 public:
-    struct VideoWriterParameter {
-        VideoWriterParameter() = default;
+    struct VideoParameter {
+        VideoParameter() = default;
 
-        VideoWriterParameter(int key_, int value_) : key(key_), value(value_) {}
+        VideoParameter(int key_, int value_) : key(key_), value(value_) {}
 
         int key{-1};
         int value{-1};
         mutable bool isConsumed{false};
     };
 
-    VideoWriterParameters() = default;
+    VideoParameters() = default;
 
-    explicit VideoWriterParameters(const std::vector<int>& params)
+    explicit VideoParameters(const std::vector<int>& params)
     {
         const auto count = params.size();
         if (count % 2 != 0)
@@ -87,13 +87,46 @@ public:
         params_.emplace_back(key, value);
     }
 
+    bool has(int key) const
+    {
+        auto it = std::find_if(params_.begin(), params_.end(),
+            [key](const VideoParameter &param)
+            {
+                return param.key == key;
+            }
+        );
+        return it != params_.end();
+    }
+
     template <class ValueType>
-    ValueType get(int key, ValueType defaultValue) const CV_NOEXCEPT
+    ValueType get(int key) const
     {
         auto it = std::find_if(params_.begin(), params_.end(),
-                               [key](const VideoWriterParameter &param) {
-                                   return param.key == key;
-                               });
+            [key](const VideoParameter &param)
+            {
+                return param.key == key;
+            }
+        );
+        if (it != params_.end())
+        {
+            it->isConsumed = true;
+            return castParameterTo<ValueType>(it->value);
+        }
+        else
+        {
+            CV_Error_(Error::StsBadArg, ("Missing value for parameter: [%d]", key));
+        }
+    }
+
+    template <class ValueType>
+    ValueType get(int key, ValueType defaultValue) const
+    {
+        auto it = std::find_if(params_.begin(), params_.end(),
+            [key](const VideoParameter &param)
+            {
+                return param.key == key;
+            }
+        );
         if (it != params_.end())
         {
             it->isConsumed = true;
@@ -105,7 +138,8 @@ public:
         }
     }
 
-    std::vector<int> getUnused() const CV_NOEXCEPT {
+    std::vector<int> getUnused() const
+    {
         std::vector<int> unusedParams;
         for (const auto &param : params_)
         {
@@ -128,8 +162,45 @@ public:
         return vint_params;
     }
 
+    bool empty() const
+    {
+        return params_.empty();
+    }
+
+    bool warnUnusedParameters() const
+    {
+        bool found = false;
+        for (const auto &param : params_)
+        {
+            if (!param.isConsumed)
+            {
+                found = true;
+                CV_LOG_INFO(NULL, "VIDEOIO: unused parameter: [" << param.key << "]=" <<
+                    cv::format("%lld / 0x%16llx", (long long)param.value, (long long)param.value));
+            }
+        }
+        return found;
+    }
+
+
 private:
-    std::vector<VideoWriterParameter> params_;
+    std::vector<VideoParameter> params_;
+};
+
+class VideoWriterParameters : public VideoParameters
+{
+public:
+    VideoWriterParameters() = default;
+
+    explicit VideoWriterParameters(const std::vector<int>& params) : VideoParameters(params) {};
+};
+
+class VideoCaptureParameters : public VideoParameters
+{
+public:
+    VideoCaptureParameters() = default;
+
+    explicit VideoCaptureParameters(const std::vector<int>& params) : VideoParameters(params) {};
 };
 
 class IVideoCapture
@@ -261,7 +332,7 @@ public:
 
 //==================================================================================================
 
-Ptr<IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const std::string &filename);
+Ptr<IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const std::string &filename, const cv::VideoCaptureParameters& params);
 Ptr<IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& filename, int fourcc,
                                                    double fps, const Size& frameSize,
                                                    const VideoWriterParameters& params);
index 884390e..274c822 100644 (file)
@@ -87,6 +87,41 @@ TEST(DISABLED_videoio_camera, v4l_read_mjpg)
     capture.release();
 }
 
+TEST(DISABLED_videoio_camera, v4l_open_mjpg)
+{
+    VideoCapture capture;
+    capture.open(0, CAP_V4L2, {
+        CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G')
+    });
+    ASSERT_TRUE(capture.isOpened());
+    std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
+    std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
+    std::cout << "     height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
+    std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
+    int fourcc = (int)capture.get(CAP_PROP_FOURCC);
+    std::cout << "FOURCC code: " << cv::format("0x%8x", fourcc) << std::endl;
+    test_readFrames(capture);
+    capture.release();
+}
+
+TEST(DISABLED_videoio_camera, v4l_open_mjpg_1280x720)
+{
+    VideoCapture capture(0, CAP_V4L2, {
+        CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'),
+        CAP_PROP_FRAME_WIDTH, 1280,
+        CAP_PROP_FRAME_HEIGHT, 720,
+    });
+    ASSERT_TRUE(capture.isOpened());
+    std::cout << "Camera 0 via " << capture.getBackendName() << " backend" << std::endl;
+    std::cout << "Frame width: " << capture.get(CAP_PROP_FRAME_WIDTH) << std::endl;
+    std::cout << "     height: " << capture.get(CAP_PROP_FRAME_HEIGHT) << std::endl;
+    std::cout << "Capturing FPS: " << capture.get(CAP_PROP_FPS) << std::endl;
+    int fourcc = (int)capture.get(CAP_PROP_FOURCC);
+    std::cout << "FOURCC code: " << cv::format("0x%8x", fourcc) << std::endl;
+    test_readFrames(capture);
+    capture.release();
+}
+
 //Following test if for capture device using PhysConn_Video_SerialDigital as crossbar input pin
 TEST(DISABLED_videoio_camera, channel6)
 {
index 4bda7f3..84c34ec 100644 (file)
@@ -459,4 +459,63 @@ TEST(videoio, mp4_orientation_no_rotation)
     ASSERT_EQ(384, frame.rows);
 }
 
+
+static void ffmpeg_check_read_raw(VideoCapture& cap)
+{
+    ASSERT_TRUE(cap.isOpened()) << "Can't open the video";
+
+    Mat data;
+    cap >> data;
+    EXPECT_EQ(CV_8UC1, data.type()) << "CV_8UC1 != " << typeToString(data.type());
+    EXPECT_TRUE(data.rows == 1 || data.cols == 1) << data.size;
+    EXPECT_EQ((size_t)29729, data.total());
+
+    cap >> data;
+    EXPECT_EQ(CV_8UC1, data.type()) << "CV_8UC1 != " << typeToString(data.type());
+    EXPECT_TRUE(data.rows == 1 || data.cols == 1) << data.size;
+    EXPECT_EQ((size_t)37118, data.total());
+}
+
+TEST(videoio_ffmpeg, open_with_property)
+{
+    if (!videoio_registry::hasBackend(CAP_FFMPEG))
+        throw SkipTestException("FFmpeg backend was not found");
+
+    string video_file = findDataFile("video/big_buck_bunny.mp4");
+    VideoCapture cap;
+    EXPECT_NO_THROW(cap.open(video_file, CAP_FFMPEG, {
+        CAP_PROP_FORMAT, -1  // demux only
+    }));
+
+    ffmpeg_check_read_raw(cap);
+}
+
+TEST(videoio_ffmpeg, create_with_property)
+{
+    if (!videoio_registry::hasBackend(CAP_FFMPEG))
+        throw SkipTestException("FFmpeg backend was not found");
+
+    string video_file = findDataFile("video/big_buck_bunny.mp4");
+    VideoCapture cap(video_file, CAP_FFMPEG, {
+        CAP_PROP_FORMAT, -1  // demux only
+    });
+
+    ffmpeg_check_read_raw(cap);
+}
+
+TEST(videoio_ffmpeg, create_with_property_badarg)
+{
+    if (!videoio_registry::hasBackend(CAP_FFMPEG))
+        throw SkipTestException("FFmpeg backend was not found");
+
+    string video_file = findDataFile("video/big_buck_bunny.mp4");
+    EXPECT_ANY_THROW(
+    {
+        VideoCapture cap(video_file, CAP_FFMPEG, {
+            CAP_PROP_FORMAT, -2  // invalid
+        });
+    });
+}
+
+
 }} // namespace