Merge pull request #16766 from VadimLevin:dev/vlevin/video_writer_params_constructor

* feature: Extend VideoWriter to accept vector of parameters

 - Add additional constructor and `open` method for `VideoWriter`
   those accept a vector of parameters
 - Move actual implementation of the `VideoWriter::open` to general method
   which accepts vector of parameters
 - Propagate parsed parameters map up to actual video backend construction

* fix: Change VideoWriter constructor description to suppress doc warning

* refactor: Rollback newlines changes

* feature: Changed VideoWriter parameters workflow

* feature: Log unused parameters in VideoWriter open

* doc: Fix VideoWriter `isColor` parameter description

* fix: int to bool VC++ conversion warning

* doc: Remove information about `isColor` flag usage.
This commit is contained in:
Vadim Levin 2020-04-28 11:38:39 +03:00 committed by GitHub
parent 152e6476d9
commit 7f90f04df2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 217 additions and 35 deletions

View File

@ -189,7 +189,9 @@ enum VideoCaptureProperties {
enum VideoWriterProperties {
VIDEOWRITER_PROP_QUALITY = 1, //!< Current quality (0..100%) of the encoded videostream. Can be adjusted dynamically in some codecs.
VIDEOWRITER_PROP_FRAMEBYTES = 2, //!< (Read-only): Size of just encoded video frame. Note that the encoding order may be different from representation order.
VIDEOWRITER_PROP_NSTRIPES = 3 //!< Number of stripes for parallel encoding. -1 for auto detection.
VIDEOWRITER_PROP_NSTRIPES = 3, //!< Number of stripes for parallel encoding. -1 for auto detection.
VIDEOWRITER_PROP_IS_COLOR = 4 //!< If it is not zero, the encoder will expect and encode color frames, otherwise it
//!< will work with grayscale frames.
};
//! @} videoio_flags_base
@ -876,7 +878,7 @@ public:
@param fps Framerate of the created video stream.
@param frameSize Size of the video frames.
@param isColor If it is not zero, the encoder will expect and encode color frames, otherwise it
will work with grayscale frames (the flag is currently supported on Windows only).
will work with grayscale frames.
@b Tips:
- With some backends `fourcc=-1` pops up the codec selection dialog from the system.
@ -896,6 +898,18 @@ public:
CV_WRAP VideoWriter(const String& filename, int apiPreference, int fourcc, double fps,
Size frameSize, bool isColor = true);
/** @overload
* The `params` parameter allows to specify extra encoder parameters encoded as pairs (paramId_1, paramValue_1, paramId_2, paramValue_2, ... .)
* see cv::VideoWriterProperties
*/
CV_WRAP VideoWriter(const String& filename, int fourcc, double fps, const Size& frameSize,
const std::vector<int>& params);
/** @overload
*/
CV_WRAP VideoWriter(const String& filename, int apiPreference, int fourcc, double fps,
const Size& frameSize, const std::vector<int>& params);
/** @brief Default destructor
The method first calls VideoWriter::release to close the already opened file.
@ -918,6 +932,16 @@ public:
CV_WRAP bool open(const String& filename, int apiPreference, int fourcc, double fps,
Size frameSize, bool isColor = true);
/** @overload
*/
CV_WRAP bool open(const String& filename, int fourcc, double fps, const Size& frameSize,
const std::vector<int>& params);
/** @overload
*/
CV_WRAP bool open(const String& filename, int apiPreference, int fourcc, double fps,
const Size& frameSize, const std::vector<int>& params);
/** @brief Returns true if video writer has been successfully initialized.
*/
CV_WRAP virtual bool isOpened() const;

View File

@ -18,7 +18,8 @@ public:
virtual ~IBackend() {}
virtual Ptr<IVideoCapture> createCapture(int camera) const = 0;
virtual Ptr<IVideoCapture> createCapture(const std::string &filename) const = 0;
virtual Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const = 0;
virtual Ptr<IVideoWriter> createWriter(const std::string& filename, int fourcc, double fps, const cv::Size& sz,
const VideoWriterParameters& params) const = 0;
};
class IBackendFactory
@ -32,7 +33,8 @@ public:
typedef Ptr<IVideoCapture> (*FN_createCaptureFile)(const std::string & filename);
typedef Ptr<IVideoCapture> (*FN_createCaptureCamera)(int camera);
typedef Ptr<IVideoWriter> (*FN_createWriter)(const std::string& filename, int fourcc, double fps, const Size& sz, bool isColor);
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);

View File

@ -243,7 +243,8 @@ public:
Ptr<IVideoCapture> createCapture(int camera) const CV_OVERRIDE;
Ptr<IVideoCapture> createCapture(const std::string &filename) const CV_OVERRIDE;
Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const CV_OVERRIDE;
Ptr<IVideoWriter> createWriter(const std::string& filename, int fourcc, double fps,
const cv::Size& sz, const VideoWriterParameters& params) const CV_OVERRIDE;
};
class PluginBackendFactory : public IBackendFactory
@ -502,7 +503,8 @@ class PluginWriter : public cv::IVideoWriter
public:
static
Ptr<PluginWriter> create(const OpenCV_VideoIO_Plugin_API_preview* plugin_api,
const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor)
const std::string& filename, int fourcc, double fps, const cv::Size& sz,
const VideoWriterParameters& params)
{
CV_Assert(plugin_api);
CvPluginWriter writer = NULL;
@ -510,6 +512,7 @@ public:
{
CV_Assert(plugin_api->Writer_release);
CV_Assert(!filename.empty());
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
if (CV_ERROR_OK == plugin_api->Writer_open(filename.c_str(), fourcc, fps, sz.width, sz.height, isColor, &writer))
{
CV_Assert(writer);
@ -597,12 +600,13 @@ Ptr<IVideoCapture> PluginBackend::createCapture(const std::string &filename) con
return Ptr<IVideoCapture>();
}
Ptr<IVideoWriter> PluginBackend::createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const
Ptr<IVideoWriter> PluginBackend::createWriter(const std::string& filename, int fourcc, double fps,
const cv::Size& sz, const VideoWriterParameters& params) const
{
try
{
if (plugin_api_)
return PluginWriter::create(plugin_api_, filename, fourcc, fps, sz, isColor); //.staticCast<IVideoWriter>();
return PluginWriter::create(plugin_api_, filename, fourcc, fps, sz, params); //.staticCast<IVideoWriter>();
}
catch (...)
{

View File

@ -34,10 +34,11 @@ public:
return fn_createCaptureFile_(filename);
return Ptr<IVideoCapture>();
}
Ptr<IVideoWriter> createWriter(const std::string &filename, int fourcc, double fps, const cv::Size &sz, bool isColor) const CV_OVERRIDE
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, isColor);
return fn_createWriter_(filename, fourcc, fps, sz, params);
return Ptr<IVideoWriter>();
}
}; // StaticBackend

View File

@ -458,6 +458,18 @@ VideoWriter::VideoWriter(const String& filename, int apiPreference, int _fourcc,
open(filename, apiPreference, _fourcc, fps, frameSize, isColor);
}
VideoWriter::VideoWriter(const cv::String& filename, int fourcc, double fps,
const cv::Size& frameSize, const std::vector<int>& params)
{
open(filename, fourcc, fps, frameSize, params);
}
VideoWriter::VideoWriter(const cv::String& filename, int apiPreference, int fourcc, double fps,
const cv::Size& frameSize, const std::vector<int>& params)
{
open(filename, apiPreference, fourcc, fps, frameSize, params);
}
void VideoWriter::release()
{
iwriter.release();
@ -471,11 +483,26 @@ VideoWriter::~VideoWriter()
bool VideoWriter::open(const String& filename, int _fourcc, double fps, Size frameSize,
bool isColor)
{
return open(filename, CAP_ANY, _fourcc, fps, frameSize, isColor);
return open(filename, CAP_ANY, _fourcc, fps, frameSize,
std::vector<int> { VIDEOWRITER_PROP_IS_COLOR, static_cast<int>(isColor) });
}
bool VideoWriter::open(const String& filename, int apiPreference, int _fourcc, double fps,
Size frameSize, bool isColor)
{
return open(filename, apiPreference, _fourcc, fps, frameSize,
std::vector<int> { VIDEOWRITER_PROP_IS_COLOR, static_cast<int>(isColor) });
}
bool VideoWriter::open(const String& filename, int fourcc, double fps, const Size& frameSize,
const std::vector<int>& params)
{
return open(filename, CAP_ANY, fourcc, fps, frameSize, params);
}
bool VideoWriter::open(const String& filename, int apiPreference, int fourcc, double fps,
const Size& frameSize, const std::vector<int>& params)
{
CV_INSTRUMENT_REGION();
@ -484,30 +511,39 @@ bool VideoWriter::open(const String& filename, int apiPreference, int _fourcc, d
release();
}
const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_Writer();
for (size_t i = 0; i < backends.size(); i++)
const VideoWriterParameters parameters(params);
for (const auto& info : videoio_registry::getAvailableBackends_Writer())
{
const VideoBackendInfo& info = backends[i];
if (apiPreference == CAP_ANY || apiPreference == info.id)
{
CV_WRITER_LOG_DEBUG(NULL,
cv::format("VIDEOIO(%s): trying writer with filename='%s' "
"fourcc=0x%08x fps=%g sz=%dx%d isColor=%d...",
info.name, filename.c_str(), (unsigned)_fourcc, fps,
frameSize.width, frameSize.height, (int)isColor));
info.name, filename.c_str(), (unsigned)fourcc, fps,
frameSize.width, frameSize.height,
parameters.get(VIDEOWRITER_PROP_IS_COLOR, true)));
CV_Assert(!info.backendFactory.empty());
const Ptr<IBackend> backend = info.backendFactory->getBackend();
if (!backend.empty())
{
try
{
iwriter = backend->createWriter(filename, _fourcc, fps, frameSize, isColor);
iwriter = backend->createWriter(filename, fourcc, fps, frameSize, parameters);
if (!iwriter.empty())
{
CV_WRITER_LOG_DEBUG(NULL,
cv::format("VIDEOIO(%s): created, isOpened=%d",
info.name, iwriter->isOpened()));
if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG)
{
for (int key: parameters.getUnused())
{
CV_LOG_WARNING(NULL,
cv::format("VIDEOIO(%s): parameter with key '%d' was unused",
info.name, key));
}
}
if (iwriter->isOpened())
{
return true;
@ -529,7 +565,7 @@ bool VideoWriter::open(const String& filename, int apiPreference, int _fourcc, d
catch (const std::exception& e)
{
CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n",
info.name, e.what()));
info.name, e.what()));
}
catch (...)
{

View File

@ -221,9 +221,12 @@ cv::Ptr<cv::IVideoCapture> cv::create_AVFoundation_capture_cam(int index)
return 0;
}
cv::Ptr<cv::IVideoWriter> cv::create_AVFoundation_writer(const std::string& filename, int fourcc, double fps, const cv::Size &frameSize, bool isColor)
cv::Ptr<cv::IVideoWriter> cv::create_AVFoundation_writer(const std::string& filename, int fourcc,
double fps, const cv::Size &frameSize,
const cv::VideoWriterParameters& params)
{
CvSize sz = { frameSize.width, frameSize.height };
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
CvVideoWriter_AVFoundation* wrt = new CvVideoWriter_AVFoundation(filename.c_str(), fourcc, fps, sz, isColor);
return cv::makePtr<cv::LegacyWriter>(wrt);
}

View File

@ -231,9 +231,12 @@ cv::Ptr<cv::IVideoCapture> cv::create_AVFoundation_capture_cam(int index)
return 0;
}
cv::Ptr<cv::IVideoWriter> cv::create_AVFoundation_writer(const std::string& filename, int fourcc, double fps, const cv::Size &frameSize, bool isColor)
cv::Ptr<cv::IVideoWriter> cv::create_AVFoundation_writer(const std::string& filename, int fourcc,
double fps, const cv::Size& frameSize,
const cv::VideoWriterParameters& params)
{
CvSize sz = { frameSize.width, frameSize.height };
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
CvVideoWriter_AVFoundation* wrt = new CvVideoWriter_AVFoundation(filename, fourcc, fps, sz, isColor);
if (wrt->isOpened())
{

View File

@ -170,9 +170,12 @@ protected:
} // namespace
cv::Ptr<cv::IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& filename, int fourcc, double fps, const cv::Size &frameSize, bool isColor)
cv::Ptr<cv::IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& filename, int fourcc,
double fps, const cv::Size& frameSize,
const VideoWriterParameters& params)
{
cv::Ptr<CvVideoWriter_FFMPEG_proxy> writer = cv::makePtr<CvVideoWriter_FFMPEG_proxy>(filename, fourcc, fps, frameSize, isColor != 0);
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
cv::Ptr<CvVideoWriter_FFMPEG_proxy> writer = cv::makePtr<CvVideoWriter_FFMPEG_proxy>(filename, fourcc, fps, frameSize, isColor);
if (writer && writer->isOpened())
return writer;
return cv::Ptr<cv::IVideoWriter>();

View File

@ -1673,9 +1673,11 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
return true;
}
Ptr<IVideoWriter> create_GStreamer_writer(const std::string &filename, int fourcc, double fps, const cv::Size &frameSize, bool isColor)
Ptr<IVideoWriter> create_GStreamer_writer(const std::string& filename, int fourcc, double fps,
const cv::Size& frameSize, const VideoWriterParameters& params)
{
CvVideoWriter_GStreamer* wrt = new CvVideoWriter_GStreamer;
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
try
{
if (wrt->open(filename, fourcc, fps, frameSize, isColor))

View File

@ -429,7 +429,8 @@ bool CvVideoWriter_Images::setProperty( int id, double value )
return false; // not supported
}
Ptr<IVideoWriter> create_Images_writer(const std::string &filename, int, double, const Size &, bool)
Ptr<IVideoWriter> create_Images_writer(const std::string &filename, int, double, const Size &,
const cv::VideoWriterParameters&)
{
CvVideoWriter_Images *writer = new CvVideoWriter_Images;

View File

@ -37,6 +37,88 @@ struct CvVideoWriter
namespace cv
{
namespace
{
template <class T>
inline T castParameterTo(int paramValue)
{
return static_cast<T>(paramValue);
}
template <>
inline bool castParameterTo(int paramValue)
{
return paramValue != 0;
}
}
class VideoWriterParameters
{
public:
struct VideoWriterParameter {
VideoWriterParameter() = default;
VideoWriterParameter(int key_, int value_) : key(key_), value(value_) {}
int key{-1};
int value{-1};
mutable bool isConsumed{false};
};
VideoWriterParameters() = default;
explicit VideoWriterParameters(const std::vector<int>& params)
{
const auto count = params.size();
if (count % 2 != 0)
{
CV_Error_(Error::StsVecLengthErr,
("Vector of VideoWriter parameters should have even length"));
}
params_.reserve(count / 2);
for (std::size_t i = 0; i < count; i += 2)
{
add(params[i], params[i + 1]);
}
}
void add(int key, int value)
{
params_.emplace_back(key, value);
}
template <class ValueType>
ValueType get(int key, ValueType defaultValue) const CV_NOEXCEPT
{
auto it = std::find_if(params_.begin(), params_.end(),
[key](const VideoWriterParameter &param) {
return param.key == key;
});
if (it != params_.end())
{
it->isConsumed = true;
return castParameterTo<ValueType>(it->value);
}
else
{
return defaultValue;
}
}
std::vector<int> getUnused() const CV_NOEXCEPT {
std::vector<int> unusedParams;
for (const auto &param : params_)
{
if (!param.isConsumed)
{
unusedParams.push_back(param.key);
}
}
return unusedParams;
}
private:
std::vector<VideoWriterParameter> params_;
};
class IVideoCapture
{
@ -168,24 +250,34 @@ public:
//==================================================================================================
Ptr<IVideoCapture> cvCreateFileCapture_FFMPEG_proxy(const std::string &filename);
Ptr<IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& filename, int fourcc, double fps, const Size &frameSize, bool isColor);
Ptr<IVideoWriter> cvCreateVideoWriter_FFMPEG_proxy(const std::string& filename, int fourcc,
double fps, const Size& frameSize,
const VideoWriterParameters& params);
Ptr<IVideoCapture> createGStreamerCapture_file(const std::string& filename);
Ptr<IVideoCapture> createGStreamerCapture_cam(int index);
Ptr<IVideoWriter> create_GStreamer_writer(const std::string& filename, int fourcc, double fps, const Size &frameSize, bool isColor);
Ptr<IVideoWriter> create_GStreamer_writer(const std::string& filename, int fourcc,
double fps, const Size& frameSize,
const VideoWriterParameters& params);
Ptr<IVideoCapture> create_MFX_capture(const std::string &filename);
Ptr<IVideoWriter> create_MFX_writer(const std::string &filename, int _fourcc, double fps, const Size &frameSize, bool isColor);
Ptr<IVideoWriter> create_MFX_writer(const std::string& filename, int _fourcc,
double fps, const Size& frameSize,
const VideoWriterParameters& params);
Ptr<IVideoCapture> create_AVFoundation_capture_file(const std::string &filename);
Ptr<IVideoCapture> create_AVFoundation_capture_cam(int index);
Ptr<IVideoWriter> create_AVFoundation_writer(const std::string& filename, int fourcc, double fps, const Size &frameSize, bool isColor);
Ptr<IVideoWriter> create_AVFoundation_writer(const std::string& filename, int fourcc,
double fps, const Size& frameSize,
const VideoWriterParameters& params);
Ptr<IVideoCapture> create_WRT_capture(int device);
Ptr<IVideoCapture> cvCreateCapture_MSMF(int index);
Ptr<IVideoCapture> cvCreateCapture_MSMF(const std::string& filename);
Ptr<IVideoWriter> cvCreateVideoWriter_MSMF(const std::string& filename, int fourcc, double fps, const Size &frameSize, bool is_color);
Ptr<IVideoWriter> cvCreateVideoWriter_MSMF(const std::string& filename, int fourcc,
double fps, const Size& frameSize,
const VideoWriterParameters& params);
Ptr<IVideoCapture> create_DShow_capture(int index);
@ -196,7 +288,9 @@ Ptr<IVideoCapture> create_OpenNI2_capture_cam( int index );
Ptr<IVideoCapture> create_OpenNI2_capture_file( const std::string &filename );
Ptr<IVideoCapture> create_Images_capture(const std::string &filename);
Ptr<IVideoWriter> create_Images_writer(const std::string &filename, int fourcc, double fps, const Size &frameSize, bool iscolor);
Ptr<IVideoWriter> create_Images_writer(const std::string& filename, int fourcc,
double fps, const Size& frameSize,
const VideoWriterParameters& params);
Ptr<IVideoCapture> create_DC1394_capture(int index);
@ -210,7 +304,9 @@ Ptr<IVideoCapture> create_XIMEA_capture_file( const std::string &serialNumber );
Ptr<IVideoCapture> create_Aravis_capture( int index );
Ptr<IVideoCapture> createMotionJpegCapture(const std::string& filename);
Ptr<IVideoWriter> createMotionJpegWriter(const std::string &filename, int fourcc, double fps, const Size &frameSize, bool iscolor);
Ptr<IVideoWriter> createMotionJpegWriter(const std::string& filename, int fourcc,
double fps, const Size& frameSize,
const VideoWriterParameters& params);
Ptr<IVideoCapture> createGPhoto2Capture(int index);
Ptr<IVideoCapture> createGPhoto2Capture(const std::string& deviceName);

View File

@ -251,10 +251,12 @@ bool VideoWriter_IntelMFX::write_one(cv::InputArray bgr)
}
}
Ptr<IVideoWriter> cv::create_MFX_writer(const std::string &filename, int _fourcc, double fps, const Size &frameSize, bool isColor)
Ptr<IVideoWriter> cv::create_MFX_writer(const std::string& filename, int _fourcc, double fps,
const Size& frameSize, const VideoWriterParameters& params)
{
if (codecIdByFourCC(_fourcc) > 0)
{
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
Ptr<VideoWriter_IntelMFX> a = makePtr<VideoWriter_IntelMFX>(filename, _fourcc, fps, frameSize, isColor);
if (a->isOpened())
return a;

View File

@ -1532,12 +1532,15 @@ void MotionJpegWriter::writeFrameData( const uchar* data, int step, int colorspa
}
Ptr<IVideoWriter> createMotionJpegWriter(const std::string &filename, int fourcc, double fps, const Size &frameSize, bool iscolor)
Ptr<IVideoWriter> createMotionJpegWriter(const std::string& filename, int fourcc,
double fps, const Size& frameSize,
const VideoWriterParameters& params)
{
if (fourcc != CV_FOURCC('M', 'J', 'P', 'G'))
return Ptr<IVideoWriter>();
Ptr<IVideoWriter> iwriter = makePtr<mjpeg::MotionJpegWriter>(filename, fps, frameSize, iscolor);
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
Ptr<IVideoWriter> iwriter = makePtr<mjpeg::MotionJpegWriter>(filename, fps, frameSize, isColor);
if( !iwriter->isOpened() )
iwriter.release();
return iwriter;

View File

@ -1656,11 +1656,13 @@ void CvVideoWriter_MSMF::write(cv::InputArray img)
}
cv::Ptr<cv::IVideoWriter> cv::cvCreateVideoWriter_MSMF( const std::string& filename, int fourcc,
double fps, const cv::Size &frameSize, bool isColor )
double fps, const cv::Size& frameSize,
const VideoWriterParameters& params)
{
cv::Ptr<CvVideoWriter_MSMF> writer = cv::makePtr<CvVideoWriter_MSMF>();
if (writer)
{
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
writer->open(filename, fourcc, fps, frameSize, isColor);
if (writer->isOpened())
return writer;