mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 00:03:03 +04:00
Merge pull request #15100 from Volskig:cam_multiplexing_function_v
Implement Camera Multiplexing API * IdideoCapture + two wrong function function waitAny Add errors catcher Stub for Python added. Sifting warnings One test added Two tests for camera and Perf tests added * Perf sync and async tests for waitAny() added, waitAnyInterior() deleted, getDeviceHandle() deleted * Variable OPENCV_TEST_CAMERA_LIST added * Without fps set * ASSERT_FAILED for environment variable * Perf tests is DISABLED_ * --Trailing whitespace * Return false from cap.cpp deleted * Two functions deleted from interface, +range for, +environment variable in test_camera * Space deleted * printf deleted, perror added * CV_WRAP deleted, cv2 cleared from stubs * -- space * default timeout added * @param changed * place of waitAny changed * --whitespace * ++function description * function description changed * revert unused changes * videoio: rework API for VideoCapture::waitAny()
This commit is contained in:
committed by
Alexander Alekhin
parent
ac2dc29525
commit
1acadd363b
@@ -319,6 +319,29 @@ double VideoCapture::get(int propId) const
|
||||
}
|
||||
|
||||
|
||||
bool VideoCapture::waitAny(const std::vector<VideoCapture>& streams, CV_OUT std::vector<int>& readyIndex, int64 timeoutNs)
|
||||
{
|
||||
CV_Assert(!streams.empty());
|
||||
|
||||
VideoCaptureAPIs backend = (VideoCaptureAPIs)streams[0].icap->getCaptureDomain();
|
||||
|
||||
for (size_t i = 1; i < streams.size(); ++i)
|
||||
{
|
||||
VideoCaptureAPIs backend_i = (VideoCaptureAPIs)streams[i].icap->getCaptureDomain();
|
||||
CV_CheckEQ((int)backend, (int)backend_i, "All captures must have the same backend");
|
||||
}
|
||||
|
||||
#if (defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO) // see cap_v4l.cpp guard
|
||||
if (backend == CAP_V4L2)
|
||||
return VideoCapture_V4L_waitAny(streams, readyIndex, timeoutNs);
|
||||
#else
|
||||
CV_UNUSED(readyIndex); CV_UNUSED(timeoutNs);
|
||||
#endif
|
||||
CV_Error(Error::StsNotImplemented, "VideoCapture::waitAny() is supported by V4L backend only");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
|
||||
|
||||
@@ -61,6 +61,15 @@ public:
|
||||
virtual int getCaptureDomain() const { return cv::CAP_ANY; } // Return the type of the capture object: CAP_FFMPEG, etc...
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
class VideoCapturePrivateAccessor
|
||||
{
|
||||
public:
|
||||
static
|
||||
IVideoCapture* getIVideoCapture(const VideoCapture& cap) { return cap.icap.get(); }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
//===================================================
|
||||
|
||||
// Wrapper
|
||||
@@ -116,6 +125,8 @@ public:
|
||||
{
|
||||
return cap ? cap->getCaptureDomain() : 0;
|
||||
}
|
||||
|
||||
CvCapture* getCvCapture() const { return cap; }
|
||||
};
|
||||
|
||||
class LegacyWriter : public IVideoWriter
|
||||
@@ -208,6 +219,11 @@ Ptr<IVideoCapture> createXINECapture(const std::string &filename);
|
||||
|
||||
Ptr<IVideoCapture> createAndroidCapture_file(const std::string &filename);
|
||||
|
||||
bool VideoCapture_V4L_waitAny(
|
||||
const std::vector<VideoCapture>& streams,
|
||||
CV_OUT std::vector<int>& ready,
|
||||
int64 timeoutNs);
|
||||
|
||||
} // cv::
|
||||
|
||||
#endif // CAP_INTERFACE_HPP
|
||||
|
||||
@@ -228,6 +228,8 @@ make & enjoy!
|
||||
#include <sys/ioctl.h>
|
||||
#include <limits>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#ifdef HAVE_CAMV4L2
|
||||
#include <asm/types.h> /* for videodev2.h */
|
||||
#include <linux/videodev2.h>
|
||||
@@ -372,6 +374,8 @@ struct CvCaptureCAM_V4L CV_FINAL : public CvCapture
|
||||
bool convertableToRgb() const;
|
||||
void convertToRgb(const Buffer ¤tBuffer);
|
||||
void releaseFrame();
|
||||
|
||||
bool havePendingFrame; // true if next .grab() should be noop, .retrive() resets this flag
|
||||
};
|
||||
|
||||
/*********************** Implementations ***************************************/
|
||||
@@ -384,7 +388,8 @@ CvCaptureCAM_V4L::CvCaptureCAM_V4L() :
|
||||
bufferSize(DEFAULT_V4L_BUFFERS),
|
||||
fps(0), convert_rgb(0), frame_allocated(false), returnFrame(false),
|
||||
channelNumber(-1), normalizePropRange(false),
|
||||
type(V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
type(V4L2_BUF_TYPE_VIDEO_CAPTURE),
|
||||
havePendingFrame(false)
|
||||
{
|
||||
frame = cvIplImage();
|
||||
memset(×tamp, 0, sizeof(timestamp));
|
||||
@@ -863,6 +868,7 @@ bool CvCaptureCAM_V4L::read_frame_v4l2()
|
||||
|
||||
bool CvCaptureCAM_V4L::tryIoctl(unsigned long ioctlCode, void *parameter) const
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "tryIoctl(handle=" << deviceHandle << ", ioctl=0x" << std::hex << ioctlCode << ", ...)")
|
||||
while (-1 == ioctl(deviceHandle, ioctlCode, parameter)) {
|
||||
if (!(errno == EBUSY || errno == EAGAIN))
|
||||
return false;
|
||||
@@ -889,7 +895,13 @@ bool CvCaptureCAM_V4L::tryIoctl(unsigned long ioctlCode, void *parameter) const
|
||||
|
||||
bool CvCaptureCAM_V4L::grabFrame()
|
||||
{
|
||||
if (FirstCapture) {
|
||||
if (havePendingFrame) // frame has been already grabbed during preroll
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FirstCapture)
|
||||
{
|
||||
/* Some general initialization must take place the first time through */
|
||||
|
||||
/* This is just a technicality, but all buffers must be filled up before any
|
||||
@@ -1939,6 +1951,8 @@ bool CvCaptureCAM_V4L::streaming(bool startStream)
|
||||
|
||||
IplImage *CvCaptureCAM_V4L::retrieveFrame(int)
|
||||
{
|
||||
havePendingFrame = false; // unlock .grab()
|
||||
|
||||
if (bufferIndex < 0)
|
||||
return &frame;
|
||||
|
||||
@@ -1989,6 +2003,109 @@ Ptr<IVideoCapture> create_V4L_capture_file(const std::string &filename)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
bool VideoCapture_V4L_deviceHandlePoll(const std::vector<int>& deviceHandles, std::vector<int>& ready, int64 timeoutNs)
|
||||
{
|
||||
CV_Assert(!deviceHandles.empty());
|
||||
const size_t N = deviceHandles.size();
|
||||
|
||||
ready.clear(); ready.reserve(N);
|
||||
|
||||
const auto poll_flags = POLLIN | POLLRDNORM | POLLERR;
|
||||
|
||||
std::vector<pollfd> fds; fds.reserve(N);
|
||||
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
int handle = deviceHandles[i];
|
||||
CV_LOG_DEBUG(NULL, "camera" << i << ": handle = " << handle);
|
||||
CV_Assert(handle != 0);
|
||||
fds.push_back(pollfd{handle, poll_flags, 0});
|
||||
}
|
||||
|
||||
int timeoutMs = -1;
|
||||
if (timeoutNs > 0)
|
||||
{
|
||||
timeoutMs = saturate_cast<int>((timeoutNs + 999999) / 1000000);
|
||||
}
|
||||
|
||||
int ret = poll(fds.data(), N, timeoutMs);
|
||||
if (ret == -1)
|
||||
{
|
||||
perror("poll error");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
return 0; // just timeout
|
||||
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
const auto& fd = fds[i];
|
||||
CV_LOG_DEBUG(NULL, "camera" << i << ": fd.revents = 0x" << std::hex << fd.revents);
|
||||
if ((fd.revents & (POLLIN | POLLRDNORM)) != 0)
|
||||
{
|
||||
ready.push_back(i);
|
||||
}
|
||||
else if ((fd.revents & POLLERR) != 0)
|
||||
{
|
||||
CV_Error_(Error::StsError, ("Error is reported for camera stream: %d (handle = %d)", (int)i, deviceHandles[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// not ready
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VideoCapture_V4L_waitAny(const std::vector<VideoCapture>& streams, CV_OUT std::vector<int>& ready, int64 timeoutNs)
|
||||
{
|
||||
CV_Assert(!streams.empty());
|
||||
|
||||
const size_t N = streams.size();
|
||||
|
||||
// unwrap internal API
|
||||
std::vector<CvCaptureCAM_V4L*> capPtr(N, NULL);
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
IVideoCapture* iCap = internal::VideoCapturePrivateAccessor::getIVideoCapture(streams[i]);
|
||||
LegacyCapture* legacyCapture = dynamic_cast<LegacyCapture*>(iCap);
|
||||
CV_Assert(legacyCapture);
|
||||
CvCapture* cvCap = legacyCapture->getCvCapture();
|
||||
CV_Assert(cvCap);
|
||||
|
||||
CvCaptureCAM_V4L *ptr_CvCaptureCAM_V4L = dynamic_cast<CvCaptureCAM_V4L*>(cvCap);
|
||||
CV_Assert(ptr_CvCaptureCAM_V4L);
|
||||
capPtr[i] = ptr_CvCaptureCAM_V4L;
|
||||
}
|
||||
|
||||
// initialize cameras streams and get handles
|
||||
std::vector<int> deviceHandles; deviceHandles.reserve(N);
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
CvCaptureCAM_V4L *ptr = capPtr[i];
|
||||
if (ptr->FirstCapture)
|
||||
{
|
||||
ptr->havePendingFrame = ptr->grabFrame();
|
||||
CV_Assert(ptr->havePendingFrame);
|
||||
// TODO: Need to filter these cameras, because frame is available
|
||||
}
|
||||
CV_Assert(ptr->deviceHandle);
|
||||
deviceHandles.push_back(ptr->deviceHandle);
|
||||
}
|
||||
|
||||
bool res = VideoCapture_V4L_deviceHandlePoll(deviceHandles, ready, timeoutNs);
|
||||
for (size_t i = 0; i < ready.size(); ++i)
|
||||
{
|
||||
int idx = ready[i];
|
||||
CvCaptureCAM_V4L *ptr = capPtr[idx];
|
||||
ptr->havePendingFrame = ptr->grabFrame();
|
||||
CV_Assert(ptr->havePendingFrame);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // cv::
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user