Skip to content

Commit 541a09b

Browse files
authored
Merge pull request opencv#18535 from joshdoe:gray16_gstreamer_writing
Add CV_16UC1/GRAY16_LE support to GStreamer backend for VideoWriter * videoio(backend): add Writer_open_with_params to plugin API This will allow arbitrary parameters to be passed to plugin backends * videoio(gstreamer): add GRAY16_LE/CV_16UC1 writing support to GStreamer This introduces a new property VIDEOWRITER_PROP_DEPTH, which defaults to CV_8U, but for GStreamer can be set to CV_16U. Also, fix another test to not fail if plugin isn't found, copying logic from the read_write test. * videoio(plugin): fix handling plugins with previous API level * videoio: coding style * fix warning
1 parent 753ccd6 commit 541a09b

File tree

10 files changed

+235
-36
lines changed

10 files changed

+235
-36
lines changed

modules/videoio/include/opencv2/videoio.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,9 @@ enum VideoWriterProperties {
194194
VIDEOWRITER_PROP_QUALITY = 1, //!< Current quality (0..100%) of the encoded videostream. Can be adjusted dynamically in some codecs.
195195
VIDEOWRITER_PROP_FRAMEBYTES = 2, //!< (Read-only): Size of just encoded video frame. Note that the encoding order may be different from representation order.
196196
VIDEOWRITER_PROP_NSTRIPES = 3, //!< Number of stripes for parallel encoding. -1 for auto detection.
197-
VIDEOWRITER_PROP_IS_COLOR = 4 //!< If it is not zero, the encoder will expect and encode color frames, otherwise it
197+
VIDEOWRITER_PROP_IS_COLOR = 4, //!< If it is not zero, the encoder will expect and encode color frames, otherwise it
198198
//!< will work with grayscale frames.
199+
VIDEOWRITER_PROP_DEPTH = 5 //!< Defaults to CV_8U.
199200
};
200201

201202
//! @} videoio_flags_base

modules/videoio/src/backend_plugin.cpp

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,15 @@ class PluginBackend: public IBackend
205205
FN_opencv_videoio_plugin_init_t fn_init = reinterpret_cast<FN_opencv_videoio_plugin_init_t>(lib_->getSymbol(init_name));
206206
if (fn_init)
207207
{
208-
plugin_api_ = fn_init(ABI_VERSION, API_VERSION, NULL);
208+
for (int supported_api_version = API_VERSION; supported_api_version >= 0; supported_api_version--)
209+
{
210+
plugin_api_ = fn_init(ABI_VERSION, supported_api_version, NULL);
211+
if (plugin_api_)
212+
break;
213+
}
209214
if (!plugin_api_)
210215
{
211-
CV_LOG_INFO(NULL, "Video I/O: plugin is incompatible: " << lib->getName());
216+
CV_LOG_INFO(NULL, "Video I/O: plugin is incompatible (can't be initialized): " << lib->getName());
212217
return;
213218
}
214219
if (plugin_api_->api_header.opencv_version_major != CV_VERSION_MAJOR)
@@ -232,8 +237,29 @@ class PluginBackend: public IBackend
232237
plugin_api_ = NULL;
233238
return;
234239
}
235-
// TODO Preview: add compatibility API/ABI checks
236-
CV_LOG_INFO(NULL, "Video I/O: loaded plugin '" << plugin_api_->api_header.api_description << "'");
240+
CV_LOG_INFO(NULL, "Video I/O: initialized '" << plugin_api_->api_header.api_description << "': built with "
241+
<< cv::format("OpenCV %d.%d (ABI/API = %d/%d)",
242+
plugin_api_->api_header.opencv_version_major, plugin_api_->api_header.opencv_version_minor,
243+
plugin_api_->api_header.min_api_version, plugin_api_->api_header.api_version)
244+
<< ", current OpenCV version is '" CV_VERSION "' (ABI/API = " << ABI_VERSION << "/" << API_VERSION << ")"
245+
);
246+
if (plugin_api_->api_header.min_api_version != ABI_VERSION) // future: range can be here
247+
{
248+
// actually this should never happen due to checks in plugin's init() function
249+
CV_LOG_ERROR(NULL, "Video I/O: plugin is not supported due to incompatible ABI = " << plugin_api_->api_header.min_api_version);
250+
plugin_api_ = NULL;
251+
return;
252+
}
253+
if (plugin_api_->api_header.api_version != API_VERSION)
254+
{
255+
CV_LOG_INFO(NULL, "Video I/O: NOTE: plugin is supported, but there is API version mismath: "
256+
<< cv::format("plugin API level (%d) != OpenCV API level (%d)", plugin_api_->api_header.api_version, API_VERSION));
257+
if (plugin_api_->api_header.api_version < API_VERSION)
258+
{
259+
CV_LOG_INFO(NULL, "Video I/O: NOTE: some functionality may be unavailable due to lack of support by plugin implementation");
260+
}
261+
}
262+
CV_LOG_INFO(NULL, "Video I/O: plugin is ready to use '" << plugin_api_->api_header.api_description << "'");
237263
}
238264
else
239265
{
@@ -508,11 +534,31 @@ class PluginWriter : public cv::IVideoWriter
508534
{
509535
CV_Assert(plugin_api);
510536
CvPluginWriter writer = NULL;
511-
if (plugin_api->Writer_open)
537+
if (plugin_api->api_header.api_version >= 1 && plugin_api->Writer_open_with_params)
538+
{
539+
CV_Assert(plugin_api->Writer_release);
540+
CV_Assert(!filename.empty());
541+
std::vector<int> vint_params = params.getIntVector();
542+
int* c_params = &vint_params[0];
543+
unsigned n_params = (unsigned)(vint_params.size() / 2);
544+
545+
if (CV_ERROR_OK == plugin_api->Writer_open_with_params(filename.c_str(), fourcc, fps, sz.width, sz.height, c_params, n_params, &writer))
546+
{
547+
CV_Assert(writer);
548+
return makePtr<PluginWriter>(plugin_api, writer);
549+
}
550+
}
551+
else if (plugin_api->Writer_open)
512552
{
513553
CV_Assert(plugin_api->Writer_release);
514554
CV_Assert(!filename.empty());
515555
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
556+
const int depth = params.get(VIDEOWRITER_PROP_DEPTH, CV_8U);
557+
if (depth != CV_8U)
558+
{
559+
CV_LOG_WARNING(NULL, "Video I/O plugin doesn't support (due to lower API level) creation of VideoWriter with depth != CV_8U");
560+
return Ptr<PluginWriter>();
561+
}
516562
if (CV_ERROR_OK == plugin_api->Writer_open(filename.c_str(), fourcc, fps, sz.width, sz.height, isColor, &writer))
517563
{
518564
CV_Assert(writer);

modules/videoio/src/cap_ffmpeg.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char
396396
static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
397397
{
398398
{
399-
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
399+
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, 0/*API_VERSION*/,
400400
CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
401401
"FFmpeg OpenCV Video I/O plugin"
402402
},
@@ -411,7 +411,8 @@ static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
411411
/* 9*/cv_writer_release,
412412
/* 10*/cv_writer_get_prop,
413413
/* 11*/cv_writer_set_prop,
414-
/* 12*/cv_writer_write
414+
/* 12*/cv_writer_write,
415+
/* 13 Writer_open_with_params*/NULL
415416
};
416417

417418
} // namespace

modules/videoio/src/cap_gstreamer.cpp

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,8 +1240,8 @@ class CvVideoWriter_GStreamer : public CvVideoWriter
12401240
{
12411241
public:
12421242
CvVideoWriter_GStreamer()
1243-
: input_pix_fmt(0),
1244-
num_frames(0), framerate(0)
1243+
: ipl_depth(CV_8U)
1244+
, input_pix_fmt(0), num_frames(0), framerate(0)
12451245
{
12461246
}
12471247
virtual ~CvVideoWriter_GStreamer() CV_OVERRIDE
@@ -1263,14 +1263,16 @@ class CvVideoWriter_GStreamer : public CvVideoWriter
12631263
int getCaptureDomain() const CV_OVERRIDE { return cv::CAP_GSTREAMER; }
12641264

12651265
bool open(const std::string &filename, int fourcc,
1266-
double fps, const Size &frameSize, bool isColor );
1266+
double fps, const Size &frameSize, bool isColor, int depth );
12671267
void close();
12681268
bool writeFrame( const IplImage* image ) CV_OVERRIDE;
1269+
1270+
int getIplDepth() const { return ipl_depth; }
12691271
protected:
12701272
const char* filenameToMimetype(const char* filename);
12711273
GSafePtr<GstElement> pipeline;
12721274
GSafePtr<GstElement> source;
1273-
1275+
int ipl_depth;
12741276
int input_pix_fmt;
12751277
int num_frames;
12761278
double framerate;
@@ -1396,6 +1398,7 @@ const char* CvVideoWriter_GStreamer::filenameToMimetype(const char *filename)
13961398
* \param fps desired framerate
13971399
* \param frameSize the size of the expected frames
13981400
* \param is_color color or grayscale
1401+
* \param depth the depth of the expected frames
13991402
* \return success
14001403
*
14011404
* We support 2 modes of operation. Either the user enters a filename and a fourcc
@@ -1408,7 +1411,8 @@ const char* CvVideoWriter_GStreamer::filenameToMimetype(const char *filename)
14081411
*
14091412
*/
14101413
bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
1411-
double fps, const cv::Size &frameSize, bool is_color )
1414+
double fps, const cv::Size &frameSize,
1415+
bool is_color, int depth )
14121416
{
14131417
// check arguments
14141418
CV_Assert(!filename.empty());
@@ -1548,6 +1552,8 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
15481552

15491553
if (fourcc == CV_FOURCC('M','J','P','G') && frameSize.height == 1)
15501554
{
1555+
CV_Assert(depth == CV_8U);
1556+
ipl_depth = IPL_DEPTH_8U;
15511557
input_pix_fmt = GST_VIDEO_FORMAT_ENCODED;
15521558
caps.attach(gst_caps_new_simple("image/jpeg",
15531559
"framerate", GST_TYPE_FRACTION, int(fps_num), int(fps_denom),
@@ -1556,6 +1562,8 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
15561562
}
15571563
else if (is_color)
15581564
{
1565+
CV_Assert(depth == CV_8U);
1566+
ipl_depth = IPL_DEPTH_8U;
15591567
input_pix_fmt = GST_VIDEO_FORMAT_BGR;
15601568
bufsize = frameSize.width * frameSize.height * 3;
15611569

@@ -1569,8 +1577,9 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
15691577
caps.attach(gst_caps_fixate(caps.detach()));
15701578
CV_Assert(caps);
15711579
}
1572-
else
1580+
else if (!is_color && depth == CV_8U)
15731581
{
1582+
ipl_depth = IPL_DEPTH_8U;
15741583
input_pix_fmt = GST_VIDEO_FORMAT_GRAY8;
15751584
bufsize = frameSize.width * frameSize.height;
15761585

@@ -1582,6 +1591,26 @@ bool CvVideoWriter_GStreamer::open( const std::string &filename, int fourcc,
15821591
NULL));
15831592
caps.attach(gst_caps_fixate(caps.detach()));
15841593
}
1594+
else if (!is_color && depth == CV_16U)
1595+
{
1596+
ipl_depth = IPL_DEPTH_16U;
1597+
input_pix_fmt = GST_VIDEO_FORMAT_GRAY16_LE;
1598+
bufsize = frameSize.width * frameSize.height * 2;
1599+
1600+
caps.attach(gst_caps_new_simple("video/x-raw",
1601+
"format", G_TYPE_STRING, "GRAY16_LE",
1602+
"width", G_TYPE_INT, frameSize.width,
1603+
"height", G_TYPE_INT, frameSize.height,
1604+
"framerate", GST_TYPE_FRACTION, gint(fps_num), gint(fps_denom),
1605+
NULL));
1606+
caps.attach(gst_caps_fixate(caps.detach()));
1607+
}
1608+
else
1609+
{
1610+
CV_WARN("unsupported depth=" << depth <<", and is_color=" << is_color << " combination");
1611+
pipeline.release();
1612+
return false;
1613+
}
15851614

15861615
gst_app_src_set_caps(GST_APP_SRC(source.get()), caps);
15871616
gst_app_src_set_stream_type(GST_APP_SRC(source.get()), GST_APP_STREAM_TYPE_STREAM);
@@ -1659,6 +1688,12 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
16591688
return false;
16601689
}
16611690
}
1691+
else if (input_pix_fmt == GST_VIDEO_FORMAT_GRAY16_LE) {
1692+
if (image->nChannels != 1 || image->depth != IPL_DEPTH_16U) {
1693+
CV_WARN("cvWriteFrame() needs images with depth = IPL_DEPTH_16U and nChannels = 1.");
1694+
return false;
1695+
}
1696+
}
16621697
else {
16631698
CV_WARN("cvWriteFrame() needs BGR or grayscale images\n");
16641699
return false;
@@ -1699,9 +1734,10 @@ Ptr<IVideoWriter> create_GStreamer_writer(const std::string& filename, int fourc
16991734
{
17001735
CvVideoWriter_GStreamer* wrt = new CvVideoWriter_GStreamer;
17011736
const bool isColor = params.get(VIDEOWRITER_PROP_IS_COLOR, true);
1737+
const int depth = params.get(VIDEOWRITER_PROP_DEPTH, CV_8U);
17021738
try
17031739
{
1704-
if (wrt->open(filename, fourcc, fps, frameSize, isColor))
1740+
if (wrt->open(filename, fourcc, fps, frameSize, isColor, depth))
17051741
return makePtr<LegacyWriter>(wrt);
17061742
delete wrt;
17071743
}
@@ -1921,15 +1957,40 @@ CvResult CV_API_CALL cv_capture_retrieve(CvPluginCapture handle, int stream_idx,
19211957
}
19221958

19231959
static
1924-
CvResult CV_API_CALL cv_writer_open(const char* filename, int fourcc, double fps, int width, int height, int isColor,
1925-
CV_OUT CvPluginWriter* handle)
1960+
CvResult CV_API_CALL cv_writer_open_with_params(
1961+
const char* filename, int fourcc, double fps, int width, int height,
1962+
int* params, unsigned n_params,
1963+
CV_OUT CvPluginWriter* handle)
19261964
{
19271965
CvVideoWriter_GStreamer* wrt = 0;
19281966
try
19291967
{
1930-
wrt = new CvVideoWriter_GStreamer();
19311968
CvSize sz = { width, height };
1932-
if(wrt && wrt->open(filename, fourcc, fps, sz, isColor))
1969+
bool isColor = true;
1970+
int depth = CV_8U;
1971+
if (params)
1972+
{
1973+
for (unsigned i = 0; i < n_params; ++i)
1974+
{
1975+
const int prop = params[i*2];
1976+
const int value = params[i*2 + 1];
1977+
switch (prop)
1978+
{
1979+
case VIDEOWRITER_PROP_IS_COLOR:
1980+
isColor = value != 0;
1981+
break;
1982+
case VIDEOWRITER_PROP_DEPTH:
1983+
depth = value;
1984+
break;
1985+
default:
1986+
// TODO emit message about non-recognized propert
1987+
// FUTURE: there should be mandatory and optional properties
1988+
return CV_ERROR_FAIL;
1989+
}
1990+
}
1991+
}
1992+
wrt = new CvVideoWriter_GStreamer();
1993+
if (wrt && wrt->open(filename, fourcc, fps, sz, isColor, depth))
19331994
{
19341995
*handle = (CvPluginWriter)wrt;
19351996
return CV_ERROR_OK;
@@ -1943,6 +2004,14 @@ CvResult CV_API_CALL cv_writer_open(const char* filename, int fourcc, double fps
19432004
return CV_ERROR_FAIL;
19442005
}
19452006

2007+
static
2008+
CvResult CV_API_CALL cv_writer_open(const char* filename, int fourcc, double fps, int width, int height, int isColor,
2009+
CV_OUT CvPluginWriter* handle)
2010+
{
2011+
int params[2] = { VIDEOWRITER_PROP_IS_COLOR, isColor };
2012+
return cv_writer_open_with_params(filename, fourcc, fps, width, height, params, 1, handle);
2013+
}
2014+
19462015
static
19472016
CvResult CV_API_CALL cv_writer_release(CvPluginWriter handle)
19482017
{
@@ -1975,7 +2044,7 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char
19752044
CvVideoWriter_GStreamer* instance = (CvVideoWriter_GStreamer*)handle;
19762045
CvSize sz = { width, height };
19772046
IplImage img;
1978-
cvInitImageHeader(&img, sz, IPL_DEPTH_8U, cn);
2047+
cvInitImageHeader(&img, sz, instance->getIplDepth(), cn);
19792048
cvSetData(&img, const_cast<unsigned char*>(data), step);
19802049
return instance->writeFrame(&img) ? CV_ERROR_OK : CV_ERROR_FAIL;
19812050
}
@@ -2003,7 +2072,8 @@ static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
20032072
/* 9*/cv_writer_release,
20042073
/* 10*/cv_writer_get_prop,
20052074
/* 11*/cv_writer_set_prop,
2006-
/* 12*/cv_writer_write
2075+
/* 12*/cv_writer_write,
2076+
/* 13*/cv_writer_open_with_params
20072077
};
20082078

20092079
} // namespace
@@ -2012,7 +2082,7 @@ const OpenCV_VideoIO_Plugin_API_preview* opencv_videoio_plugin_init_v0(int reque
20122082
{
20132083
if (requested_abi_version != 0)
20142084
return NULL;
2015-
if (requested_api_version != 0)
2085+
if (requested_api_version != 0 && requested_api_version != 1)
20162086
return NULL;
20172087
return &cv::plugin_api_v0;
20182088
}

modules/videoio/src/cap_interface.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ class VideoWriterParameters
116116
}
117117
return unusedParams;
118118
}
119+
120+
std::vector<int> getIntVector() const
121+
{
122+
std::vector<int> vint_params;
123+
for (const auto& param : params_)
124+
{
125+
vint_params.push_back(param.key);
126+
vint_params.push_back(param.value);
127+
}
128+
return vint_params;
129+
}
130+
119131
private:
120132
std::vector<VideoWriterParameter> params_;
121133
};

modules/videoio/src/cap_mfx_plugin.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char
188188
static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
189189
{
190190
{
191-
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
191+
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, 0/*API_VERSION*/,
192192
CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
193193
"MediaSDK OpenCV Video I/O plugin"
194194
},
@@ -203,7 +203,8 @@ static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
203203
/* 9*/cv_writer_release,
204204
/* 10*/cv_writer_get_prop,
205205
/* 11*/cv_writer_set_prop,
206-
/* 12*/cv_writer_write
206+
/* 12*/cv_writer_write,
207+
/* 13 Writer_open_with_params*/NULL
207208
};
208209

209210
} // namespace

modules/videoio/src/cap_msmf.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1866,7 +1866,7 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter handle, const unsigned char*
18661866
static const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
18671867
{
18681868
{
1869-
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
1869+
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, 0/*API_VERSION*/,
18701870
CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
18711871
"Microsoft Media Foundation OpenCV Video I/O plugin"
18721872
},

modules/videoio/src/cap_ueye.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ CvResult CV_API_CALL cv_writer_write(CvPluginWriter /*handle*/, const unsigned c
467467
const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
468468
{
469469
{
470-
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, API_VERSION,
470+
sizeof(OpenCV_VideoIO_Plugin_API_preview), ABI_VERSION, 0/*API_VERSION*/,
471471
CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS,
472472
"uEye OpenCV Video I/O plugin"
473473
},
@@ -482,7 +482,8 @@ const OpenCV_VideoIO_Plugin_API_preview plugin_api_v0 =
482482
/* 9*/cv_writer_release,
483483
/* 10*/cv_writer_get_prop,
484484
/* 11*/cv_writer_set_prop,
485-
/* 12*/cv_writer_write
485+
/* 12*/cv_writer_write,
486+
/* 13 Writer_open_with_params*/NULL
486487
};
487488
} // namespace
488489
} // namespace cv

0 commit comments

Comments
 (0)