1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
8 //
9 //
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
21 //
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
25 //
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "precomp.hpp"
43
44 #include "opencv2/videoio/registry.hpp"
45 #include "videoio_registry.hpp"
46
47 namespace cv {
48
49 static bool param_VIDEOIO_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOIO_DEBUG", false);
50 static bool param_VIDEOCAPTURE_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOCAPTURE_DEBUG", false);
51 static bool param_VIDEOWRITER_DEBUG = utils::getConfigurationParameterBool("OPENCV_VIDEOWRITER_DEBUG", false);
52
53 #define CV_CAPTURE_LOG_DEBUG(tag, ...) \
54 if (param_VIDEOIO_DEBUG || param_VIDEOCAPTURE_DEBUG) \
55 { \
56 CV_LOG_WARNING(nullptr, __VA_ARGS__); \
57 }
58
59 #define CV_WRITER_LOG_DEBUG(tag, ...) \
60 if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG) \
61 { \
62 CV_LOG_WARNING(nullptr, __VA_ARGS__) \
63 }
64
operator ()(CvCapture * obj) const65 void DefaultDeleter<CvCapture>::operator ()(CvCapture* obj) const { cvReleaseCapture(&obj); }
operator ()(CvVideoWriter * obj) const66 void DefaultDeleter<CvVideoWriter>::operator ()(CvVideoWriter* obj) const { cvReleaseVideoWriter(&obj); }
67
68
VideoCapture()69 VideoCapture::VideoCapture() : throwOnFail(false)
70 {}
71
VideoCapture(const String & filename,int apiPreference)72 VideoCapture::VideoCapture(const String& filename, int apiPreference) : throwOnFail(false)
73 {
74 CV_TRACE_FUNCTION();
75 open(filename, apiPreference);
76 }
77
VideoCapture(const String & filename,int apiPreference,const std::vector<int> & params)78 VideoCapture::VideoCapture(const String& filename, int apiPreference, const std::vector<int>& params)
79 : throwOnFail(false)
80 {
81 CV_TRACE_FUNCTION();
82 open(filename, apiPreference, params);
83 }
84
VideoCapture(int index,int apiPreference)85 VideoCapture::VideoCapture(int index, int apiPreference) : throwOnFail(false)
86 {
87 CV_TRACE_FUNCTION();
88 open(index, apiPreference);
89 }
90
VideoCapture(int index,int apiPreference,const std::vector<int> & params)91 VideoCapture::VideoCapture(int index, int apiPreference, const std::vector<int>& params)
92 : throwOnFail(false)
93 {
94 CV_TRACE_FUNCTION();
95 open(index, apiPreference, params);
96 }
97
~VideoCapture()98 VideoCapture::~VideoCapture()
99 {
100 CV_TRACE_FUNCTION();
101 icap.release();
102 }
103
open(const String & filename,int apiPreference)104 bool VideoCapture::open(const String& filename, int apiPreference)
105 {
106 return open(filename, apiPreference, std::vector<int>());
107 }
108
open(const String & filename,int apiPreference,const std::vector<int> & params)109 bool VideoCapture::open(const String& filename, int apiPreference, const std::vector<int>& params)
110 {
111 CV_INSTRUMENT_REGION();
112
113 if (isOpened())
114 {
115 release();
116 }
117
118 const VideoCaptureParameters parameters(params);
119 const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByFilename();
120 for (size_t i = 0; i < backends.size(); i++)
121 {
122 const VideoBackendInfo& info = backends[i];
123 if (apiPreference == CAP_ANY || apiPreference == info.id)
124 {
125
126 CV_CAPTURE_LOG_DEBUG(NULL,
127 cv::format("VIDEOIO(%s): trying capture filename='%s' ...",
128 info.name, filename.c_str()));
129 CV_Assert(!info.backendFactory.empty());
130 const Ptr<IBackend> backend = info.backendFactory->getBackend();
131 if (!backend.empty())
132 {
133 try
134 {
135 icap = backend->createCapture(filename, parameters);
136 if (!icap.empty())
137 {
138 CV_CAPTURE_LOG_DEBUG(NULL,
139 cv::format("VIDEOIO(%s): created, isOpened=%d",
140 info.name, icap->isOpened()));
141 if (icap->isOpened())
142 {
143 return true;
144 }
145 icap.release();
146 }
147 else
148 {
149 CV_CAPTURE_LOG_DEBUG(NULL,
150 cv::format("VIDEOIO(%s): can't create capture",
151 info.name));
152 }
153 }
154 catch (const cv::Exception& e)
155 {
156 if (throwOnFail && apiPreference != CAP_ANY)
157 {
158 throw;
159 }
160 CV_LOG_ERROR(NULL,
161 cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n",
162 info.name, e.what()));
163 }
164 catch (const std::exception& e)
165 {
166 if (throwOnFail && apiPreference != CAP_ANY)
167 {
168 throw;
169 }
170 CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n",
171 info.name, e.what()));
172 }
173 catch (...)
174 {
175 if (throwOnFail && apiPreference != CAP_ANY)
176 {
177 throw;
178 }
179 CV_LOG_ERROR(NULL,
180 cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n",
181 info.name));
182 }
183 }
184 else
185 {
186 CV_CAPTURE_LOG_DEBUG(NULL,
187 cv::format("VIDEOIO(%s): backend is not available "
188 "(plugin is missing, or can't be loaded due "
189 "dependencies or it is not compatible)",
190 info.name));
191 }
192 }
193 }
194
195 if (throwOnFail)
196 {
197 CV_Error_(Error::StsError, ("could not open '%s'", filename.c_str()));
198 }
199
200 return false;
201 }
202
open(int cameraNum,int apiPreference)203 bool VideoCapture::open(int cameraNum, int apiPreference)
204 {
205 return open(cameraNum, apiPreference, std::vector<int>());
206 }
207
open(int cameraNum,int apiPreference,const std::vector<int> & params)208 bool VideoCapture::open(int cameraNum, int apiPreference, const std::vector<int>& params)
209 {
210 CV_TRACE_FUNCTION();
211
212 if (isOpened())
213 {
214 release();
215 }
216
217 if (apiPreference == CAP_ANY)
218 {
219 // interpret preferred interface (0 = autodetect)
220 int backendID = (cameraNum / 100) * 100;
221 if (backendID)
222 {
223 cameraNum %= 100;
224 apiPreference = backendID;
225 }
226 }
227
228 const VideoCaptureParameters parameters(params);
229 const std::vector<VideoBackendInfo> backends = cv::videoio_registry::getAvailableBackends_CaptureByIndex();
230 for (size_t i = 0; i < backends.size(); i++)
231 {
232 const VideoBackendInfo& info = backends[i];
233 if (apiPreference == CAP_ANY || apiPreference == info.id)
234 {
235 CV_CAPTURE_LOG_DEBUG(NULL,
236 cv::format("VIDEOIO(%s): trying capture cameraNum=%d ...",
237 info.name, cameraNum));
238
239 CV_Assert(!info.backendFactory.empty());
240 const Ptr<IBackend> backend = info.backendFactory->getBackend();
241 if (!backend.empty())
242 {
243 try
244 {
245 icap = backend->createCapture(cameraNum, parameters);
246 if (!icap.empty())
247 {
248 CV_CAPTURE_LOG_DEBUG(NULL,
249 cv::format("VIDEOIO(%s): created, isOpened=%d",
250 info.name, icap->isOpened()));
251 if (icap->isOpened())
252 {
253 return true;
254 }
255 icap.release();
256 }
257 else
258 {
259 CV_CAPTURE_LOG_DEBUG(NULL,
260 cv::format("VIDEOIO(%s): can't create capture",
261 info.name));
262 }
263 }
264 catch (const cv::Exception& e)
265 {
266 if (throwOnFail && apiPreference != CAP_ANY)
267 {
268 throw;
269 }
270 CV_LOG_ERROR(NULL,
271 cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n",
272 info.name, e.what()));
273 }
274 catch (const std::exception& e)
275 {
276 if (throwOnFail && apiPreference != CAP_ANY)
277 {
278 throw;
279 }
280 CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n",
281 info.name, e.what()));
282 }
283 catch (...)
284 {
285 if (throwOnFail && apiPreference != CAP_ANY)
286 {
287 throw;
288 }
289 CV_LOG_ERROR(NULL,
290 cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n",
291 info.name));
292 }
293 }
294 else
295 {
296 CV_CAPTURE_LOG_DEBUG(NULL,
297 cv::format("VIDEOIO(%s): backend is not available "
298 "(plugin is missing, or can't be loaded due "
299 "dependencies or it is not compatible)",
300 info.name));
301 }
302 }
303 }
304
305 if (throwOnFail)
306 {
307 CV_Error_(Error::StsError, ("could not open camera %d", cameraNum));
308 }
309
310 return false;
311 }
312
isOpened() const313 bool VideoCapture::isOpened() const
314 {
315 return !icap.empty() ? icap->isOpened() : false;
316 }
317
getBackendName() const318 String VideoCapture::getBackendName() const
319 {
320 int api = 0;
321 if (icap)
322 {
323 api = icap->isOpened() ? icap->getCaptureDomain() : 0;
324 }
325 CV_Assert(api != 0);
326 return cv::videoio_registry::getBackendName(static_cast<VideoCaptureAPIs>(api));
327 }
328
release()329 void VideoCapture::release()
330 {
331 CV_TRACE_FUNCTION();
332 icap.release();
333 }
334
grab()335 bool VideoCapture::grab()
336 {
337 CV_INSTRUMENT_REGION();
338 bool ret = !icap.empty() ? icap->grabFrame() : false;
339 if (!ret && throwOnFail)
340 {
341 CV_Error(Error::StsError, "");
342 }
343 return ret;
344 }
345
retrieve(OutputArray image,int channel)346 bool VideoCapture::retrieve(OutputArray image, int channel)
347 {
348 CV_INSTRUMENT_REGION();
349
350 bool ret = false;
351 if (!icap.empty())
352 {
353 ret = icap->retrieveFrame(channel, image);
354 }
355 if (!ret && throwOnFail)
356 {
357 CV_Error_(Error::StsError, ("could not retrieve channel %d", channel));
358 }
359 return ret;
360 }
361
read(OutputArray image)362 bool VideoCapture::read(OutputArray image)
363 {
364 CV_INSTRUMENT_REGION();
365
366 if (grab())
367 {
368 retrieve(image);
369 } else {
370 image.release();
371 }
372 return !image.empty();
373 }
374
operator >>(Mat & image)375 VideoCapture& VideoCapture::operator >> (Mat& image)
376 {
377 #ifdef WINRT_VIDEO
378 // FIXIT grab/retrieve methods() should work too
379 if (grab())
380 {
381 if (retrieve(image))
382 {
383 std::lock_guard<std::mutex> lock(VideoioBridge::getInstance().inputBufferMutex);
384 VideoioBridge& bridge = VideoioBridge::getInstance();
385
386 // double buffering
387 bridge.swapInputBuffers();
388 auto p = bridge.frontInputPtr;
389
390 bridge.bIsFrameNew = false;
391
392 // needed here because setting Mat 'image' is not allowed by OutputArray in read()
393 Mat m(bridge.getHeight(), bridge.getWidth(), CV_8UC3, p);
394 image = m;
395 }
396 }
397 #else
398 read(image);
399 #endif
400 return *this;
401 }
402
operator >>(UMat & image)403 VideoCapture& VideoCapture::operator >> (UMat& image)
404 {
405 CV_INSTRUMENT_REGION();
406
407 read(image);
408 return *this;
409 }
410
set(int propId,double value)411 bool VideoCapture::set(int propId, double value)
412 {
413 CV_CheckNE(propId, (int)CAP_PROP_BACKEND, "Can't set read-only property");
414 bool ret = !icap.empty() ? icap->setProperty(propId, value) : false;
415 if (!ret && throwOnFail)
416 {
417 CV_Error_(Error::StsError, ("could not set prop %d = %f", propId, value));
418 }
419 return ret;
420 }
421
get(int propId) const422 double VideoCapture::get(int propId) const
423 {
424 if (propId == CAP_PROP_BACKEND)
425 {
426 int api = 0;
427 if (icap && icap->isOpened())
428 {
429 api = icap->getCaptureDomain();
430 }
431 if (api <= 0)
432 {
433 return -1.0;
434 }
435 return static_cast<double>(api);
436 }
437 return !icap.empty() ? icap->getProperty(propId) : 0;
438 }
439
440
waitAny(const std::vector<VideoCapture> & streams,CV_OUT std::vector<int> & readyIndex,int64 timeoutNs)441 bool VideoCapture::waitAny(const std::vector<VideoCapture>& streams,
442 CV_OUT std::vector<int>& readyIndex, int64 timeoutNs)
443 {
444 CV_Assert(!streams.empty());
445
446 VideoCaptureAPIs backend = (VideoCaptureAPIs)streams[0].icap->getCaptureDomain();
447
448 for (size_t i = 1; i < streams.size(); ++i)
449 {
450 VideoCaptureAPIs backend_i = (VideoCaptureAPIs)streams[i].icap->getCaptureDomain();
451 CV_CheckEQ((int)backend, (int)backend_i, "All captures must have the same backend");
452 }
453
454 #if (defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO) // see cap_v4l.cpp guard
455 if (backend == CAP_V4L2)
456 {
457 return VideoCapture_V4L_waitAny(streams, readyIndex, timeoutNs);
458 }
459 #else
460 CV_UNUSED(readyIndex);
461 CV_UNUSED(timeoutNs);
462 #endif
463 CV_Error(Error::StsNotImplemented, "VideoCapture::waitAny() is supported by V4L backend only");
464 }
465
466
467 //=================================================================================================
468
469
470
VideoWriter()471 VideoWriter::VideoWriter()
472 {}
473
VideoWriter(const String & filename,int _fourcc,double fps,Size frameSize,bool isColor)474 VideoWriter::VideoWriter(const String& filename, int _fourcc, double fps, Size frameSize,
475 bool isColor)
476 {
477 open(filename, _fourcc, fps, frameSize, isColor);
478 }
479
480
VideoWriter(const String & filename,int apiPreference,int _fourcc,double fps,Size frameSize,bool isColor)481 VideoWriter::VideoWriter(const String& filename, int apiPreference, int _fourcc, double fps,
482 Size frameSize, bool isColor)
483 {
484 open(filename, apiPreference, _fourcc, fps, frameSize, isColor);
485 }
486
VideoWriter(const cv::String & filename,int fourcc,double fps,const cv::Size & frameSize,const std::vector<int> & params)487 VideoWriter::VideoWriter(const cv::String& filename, int fourcc, double fps,
488 const cv::Size& frameSize, const std::vector<int>& params)
489 {
490 open(filename, fourcc, fps, frameSize, params);
491 }
492
VideoWriter(const cv::String & filename,int apiPreference,int fourcc,double fps,const cv::Size & frameSize,const std::vector<int> & params)493 VideoWriter::VideoWriter(const cv::String& filename, int apiPreference, int fourcc, double fps,
494 const cv::Size& frameSize, const std::vector<int>& params)
495 {
496 open(filename, apiPreference, fourcc, fps, frameSize, params);
497 }
498
release()499 void VideoWriter::release()
500 {
501 iwriter.release();
502 }
503
~VideoWriter()504 VideoWriter::~VideoWriter()
505 {
506 release();
507 }
508
open(const String & filename,int _fourcc,double fps,Size frameSize,bool isColor)509 bool VideoWriter::open(const String& filename, int _fourcc, double fps, Size frameSize,
510 bool isColor)
511 {
512 return open(filename, CAP_ANY, _fourcc, fps, frameSize,
513 std::vector<int> { VIDEOWRITER_PROP_IS_COLOR, static_cast<int>(isColor) });
514 }
515
open(const String & filename,int apiPreference,int _fourcc,double fps,Size frameSize,bool isColor)516 bool VideoWriter::open(const String& filename, int apiPreference, int _fourcc, double fps,
517 Size frameSize, bool isColor)
518 {
519 return open(filename, apiPreference, _fourcc, fps, frameSize,
520 std::vector<int> { VIDEOWRITER_PROP_IS_COLOR, static_cast<int>(isColor) });
521 }
522
523
open(const String & filename,int fourcc,double fps,const Size & frameSize,const std::vector<int> & params)524 bool VideoWriter::open(const String& filename, int fourcc, double fps, const Size& frameSize,
525 const std::vector<int>& params)
526 {
527 return open(filename, CAP_ANY, fourcc, fps, frameSize, params);
528 }
529
open(const String & filename,int apiPreference,int fourcc,double fps,const Size & frameSize,const std::vector<int> & params)530 bool VideoWriter::open(const String& filename, int apiPreference, int fourcc, double fps,
531 const Size& frameSize, const std::vector<int>& params)
532 {
533 CV_INSTRUMENT_REGION();
534
535 if (isOpened())
536 {
537 release();
538 }
539
540 const VideoWriterParameters parameters(params);
541 for (const auto& info : videoio_registry::getAvailableBackends_Writer())
542 {
543 if (apiPreference == CAP_ANY || apiPreference == info.id)
544 {
545 CV_WRITER_LOG_DEBUG(NULL,
546 cv::format("VIDEOIO(%s): trying writer with filename='%s' "
547 "fourcc=0x%08x fps=%g sz=%dx%d isColor=%d...",
548 info.name, filename.c_str(), (unsigned)fourcc, fps,
549 frameSize.width, frameSize.height,
550 parameters.get(VIDEOWRITER_PROP_IS_COLOR, true)));
551 CV_Assert(!info.backendFactory.empty());
552 const Ptr<IBackend> backend = info.backendFactory->getBackend();
553 if (!backend.empty())
554 {
555 try
556 {
557 iwriter = backend->createWriter(filename, fourcc, fps, frameSize, parameters);
558 if (!iwriter.empty())
559 {
560
561 CV_WRITER_LOG_DEBUG(NULL,
562 cv::format("VIDEOIO(%s): created, isOpened=%d",
563 info.name, iwriter->isOpened()));
564 if (param_VIDEOIO_DEBUG || param_VIDEOWRITER_DEBUG)
565 {
566 for (int key: parameters.getUnused())
567 {
568 CV_LOG_WARNING(NULL,
569 cv::format("VIDEOIO(%s): parameter with key '%d' was unused",
570 info.name, key));
571 }
572 }
573 if (iwriter->isOpened())
574 {
575 return true;
576 }
577 iwriter.release();
578 }
579 else
580 {
581 CV_WRITER_LOG_DEBUG(NULL, cv::format("VIDEOIO(%s): can't create writer",
582 info.name));
583 }
584 }
585 catch (const cv::Exception& e)
586 {
587 CV_LOG_ERROR(NULL,
588 cv::format("VIDEOIO(%s): raised OpenCV exception:\n\n%s\n",
589 info.name, e.what()));
590 }
591 catch (const std::exception& e)
592 {
593 CV_LOG_ERROR(NULL, cv::format("VIDEOIO(%s): raised C++ exception:\n\n%s\n",
594 info.name, e.what()));
595 }
596 catch (...)
597 {
598 CV_LOG_ERROR(NULL,
599 cv::format("VIDEOIO(%s): raised unknown C++ exception!\n\n",
600 info.name));
601 }
602 }
603 else
604 {
605 CV_WRITER_LOG_DEBUG(NULL,
606 cv::format("VIDEOIO(%s): backend is not available "
607 "(plugin is missing, or can't be loaded due "
608 "dependencies or it is not compatible)",
609 info.name));
610 }
611 }
612 }
613 return false;
614 }
615
isOpened() const616 bool VideoWriter::isOpened() const
617 {
618 return !iwriter.empty();
619 }
620
621
set(int propId,double value)622 bool VideoWriter::set(int propId, double value)
623 {
624 CV_CheckNE(propId, (int)CAP_PROP_BACKEND, "Can't set read-only property");
625
626 if (!iwriter.empty())
627 {
628 return iwriter->setProperty(propId, value);
629 }
630 return false;
631 }
632
get(int propId) const633 double VideoWriter::get(int propId) const
634 {
635 if (propId == CAP_PROP_BACKEND)
636 {
637 int api = 0;
638 if (iwriter)
639 {
640 api = iwriter->getCaptureDomain();
641 }
642 return (api <= 0) ? -1. : static_cast<double>(api);
643 }
644 if (!iwriter.empty())
645 {
646 return iwriter->getProperty(propId);
647 }
648 return 0.;
649 }
650
getBackendName() const651 String VideoWriter::getBackendName() const
652 {
653 int api = 0;
654 if (iwriter)
655 {
656 api = iwriter->getCaptureDomain();
657 }
658 CV_Assert(api != 0);
659 return cv::videoio_registry::getBackendName(static_cast<VideoCaptureAPIs>(api));
660 }
661
write(InputArray image)662 void VideoWriter::write(InputArray image)
663 {
664 CV_INSTRUMENT_REGION();
665
666 if (iwriter)
667 {
668 iwriter->write(image);
669 }
670 }
671
operator <<(const Mat & image)672 VideoWriter& VideoWriter::operator << (const Mat& image)
673 {
674 CV_INSTRUMENT_REGION();
675
676 write(image);
677 return *this;
678 }
679
operator <<(const UMat & image)680 VideoWriter& VideoWriter::operator << (const UMat& image)
681 {
682 CV_INSTRUMENT_REGION();
683 write(image);
684 return *this;
685 }
686
687 // FIXIT OpenCV 4.0: make inline
fourcc(char c1,char c2,char c3,char c4)688 int VideoWriter::fourcc(char c1, char c2, char c3, char c4)
689 {
690 return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24);
691 }
692
693 } // namespace cv
694