Commit cdc46978 authored by Alexander Alekhin's avatar Alexander Alekhin

Merge pull request #15978 from alalek:videoio_refactor_v4l

parents 5ff1faba 501ff7f0
...@@ -278,6 +278,32 @@ make & enjoy! ...@@ -278,6 +278,32 @@ make & enjoy!
namespace cv { namespace cv {
static const char* decode_ioctl_code(unsigned long ioctlCode)
{
switch (ioctlCode)
{
#define CV_ADD_IOCTL_CODE(id) case id: return #id
CV_ADD_IOCTL_CODE(VIDIOC_G_FMT);
CV_ADD_IOCTL_CODE(VIDIOC_S_FMT);
CV_ADD_IOCTL_CODE(VIDIOC_REQBUFS);
CV_ADD_IOCTL_CODE(VIDIOC_DQBUF);
CV_ADD_IOCTL_CODE(VIDIOC_QUERYCAP);
CV_ADD_IOCTL_CODE(VIDIOC_S_PARM);
CV_ADD_IOCTL_CODE(VIDIOC_G_PARM);
CV_ADD_IOCTL_CODE(VIDIOC_QUERYBUF);
CV_ADD_IOCTL_CODE(VIDIOC_QBUF);
CV_ADD_IOCTL_CODE(VIDIOC_STREAMON);
CV_ADD_IOCTL_CODE(VIDIOC_STREAMOFF);
CV_ADD_IOCTL_CODE(VIDIOC_ENUMINPUT);
CV_ADD_IOCTL_CODE(VIDIOC_G_INPUT);
CV_ADD_IOCTL_CODE(VIDIOC_S_INPUT);
CV_ADD_IOCTL_CODE(VIDIOC_G_CTRL);
CV_ADD_IOCTL_CODE(VIDIOC_S_CTRL);
#undef CV_ADD_IOCTL_CODE
}
return "unknown";
}
/* Device Capture Objects */ /* Device Capture Objects */
/* V4L2 structure */ /* V4L2 structure */
struct Buffer struct Buffer
...@@ -299,6 +325,9 @@ struct CvCaptureCAM_V4L CV_FINAL : public CvCapture ...@@ -299,6 +325,9 @@ struct CvCaptureCAM_V4L CV_FINAL : public CvCapture
int getCaptureDomain() /*const*/ CV_OVERRIDE { return cv::CAP_V4L; } int getCaptureDomain() /*const*/ CV_OVERRIDE { return cv::CAP_V4L; }
int deviceHandle; int deviceHandle;
bool v4l_buffersRequested;
bool v4l_streamStarted;
int bufferIndex; int bufferIndex;
bool FirstCapture; bool FirstCapture;
String deviceName; String deviceName;
...@@ -339,6 +368,8 @@ struct CvCaptureCAM_V4L CV_FINAL : public CvCapture ...@@ -339,6 +368,8 @@ struct CvCaptureCAM_V4L CV_FINAL : public CvCapture
bool open(const char* deviceName); bool open(const char* deviceName);
bool isOpened() const; bool isOpened() const;
void closeDevice();
virtual double getProperty(int) const CV_OVERRIDE; virtual double getProperty(int) const CV_OVERRIDE;
virtual bool setProperty(int, double) CV_OVERRIDE; virtual bool setProperty(int, double) CV_OVERRIDE;
virtual bool grabFrame() CV_OVERRIDE; virtual bool grabFrame() CV_OVERRIDE;
...@@ -373,7 +404,10 @@ struct CvCaptureCAM_V4L CV_FINAL : public CvCapture ...@@ -373,7 +404,10 @@ struct CvCaptureCAM_V4L CV_FINAL : public CvCapture
/*********************** Implementations ***************************************/ /*********************** Implementations ***************************************/
CvCaptureCAM_V4L::CvCaptureCAM_V4L() : CvCaptureCAM_V4L::CvCaptureCAM_V4L() :
deviceHandle(-1), bufferIndex(-1), deviceHandle(-1),
v4l_buffersRequested(false),
v4l_streamStarted(false),
bufferIndex(-1),
FirstCapture(true), FirstCapture(true),
palette(0), palette(0),
width(0), height(0), width_set(0), height_set(0), width(0), height(0), width_set(0), height_set(0),
...@@ -386,11 +420,32 @@ CvCaptureCAM_V4L::CvCaptureCAM_V4L() : ...@@ -386,11 +420,32 @@ CvCaptureCAM_V4L::CvCaptureCAM_V4L() :
memset(&timestamp, 0, sizeof(timestamp)); memset(&timestamp, 0, sizeof(timestamp));
} }
CvCaptureCAM_V4L::~CvCaptureCAM_V4L() { CvCaptureCAM_V4L::~CvCaptureCAM_V4L()
streaming(false); {
releaseBuffers(); try
{
closeDevice();
}
catch (...)
{
CV_LOG_WARNING(NULL, "VIDEOIO(V4L2): unable properly close device: " << deviceName);
if (deviceHandle != -1)
close(deviceHandle);
}
}
void CvCaptureCAM_V4L::closeDevice()
{
if (v4l_streamStarted)
streaming(false);
if (v4l_buffersRequested)
releaseBuffers();
if(deviceHandle != -1) if(deviceHandle != -1)
{
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): close(" << deviceHandle << ")");
close(deviceHandle); close(deviceHandle);
}
deviceHandle = -1;
} }
bool CvCaptureCAM_V4L::isOpened() const bool CvCaptureCAM_V4L::isOpened() const
...@@ -406,7 +461,7 @@ bool CvCaptureCAM_V4L::try_palette_v4l2() ...@@ -406,7 +461,7 @@ bool CvCaptureCAM_V4L::try_palette_v4l2()
form.fmt.pix.field = V4L2_FIELD_ANY; form.fmt.pix.field = V4L2_FIELD_ANY;
form.fmt.pix.width = width; form.fmt.pix.width = width;
form.fmt.pix.height = height; form.fmt.pix.height = height;
if (!tryIoctl(VIDIOC_S_FMT, &form)) if (!tryIoctl(VIDIOC_S_FMT, &form, true))
{ {
return false; return false;
} }
...@@ -451,9 +506,7 @@ bool CvCaptureCAM_V4L::try_init_v4l2() ...@@ -451,9 +506,7 @@ bool CvCaptureCAM_V4L::try_init_v4l2()
// The cv::CAP_PROP_MODE used for set the video input channel number // The cv::CAP_PROP_MODE used for set the video input channel number
if (!setVideoInputChannel()) if (!setVideoInputChannel())
{ {
#ifndef NDEBUG CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): Unable to set Video Input Channel");
fprintf(stderr, "(DEBUG) V4L2: Unable to set Video Input Channel.");
#endif
return false; return false;
} }
...@@ -461,16 +514,14 @@ bool CvCaptureCAM_V4L::try_init_v4l2() ...@@ -461,16 +514,14 @@ bool CvCaptureCAM_V4L::try_init_v4l2()
capability = v4l2_capability(); capability = v4l2_capability();
if (!tryIoctl(VIDIOC_QUERYCAP, &capability)) if (!tryIoctl(VIDIOC_QUERYCAP, &capability))
{ {
#ifndef NDEBUG CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): Unable to query capability");
fprintf(stderr, "(DEBUG) V4L2: Unable to query capability.");
#endif
return false; return false;
} }
if ((capability.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) if ((capability.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0)
{ {
/* Nope. */ /* Nope. */
fprintf(stderr, "VIDEOIO ERROR: V4L2: Unable to capture video memory."); CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): not supported - device is unable to capture video (missing V4L2_CAP_VIDEO_CAPTURE)");
return false; return false;
} }
return true; return true;
...@@ -479,10 +530,18 @@ bool CvCaptureCAM_V4L::try_init_v4l2() ...@@ -479,10 +530,18 @@ bool CvCaptureCAM_V4L::try_init_v4l2()
bool CvCaptureCAM_V4L::autosetup_capture_mode_v4l2() bool CvCaptureCAM_V4L::autosetup_capture_mode_v4l2()
{ {
//in case palette is already set and works, no need to setup. //in case palette is already set and works, no need to setup.
if (palette != 0 && try_palette_v4l2()) { if (palette != 0)
return true; {
} else if (errno == EBUSY) { if (try_palette_v4l2())
return false; {
return true;
}
else if (errno == EBUSY)
{
CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): device is busy");
closeDevice();
return false;
}
} }
__u32 try_order[] = { __u32 try_order[] = {
V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_BGR24,
...@@ -510,6 +569,10 @@ bool CvCaptureCAM_V4L::autosetup_capture_mode_v4l2() ...@@ -510,6 +569,10 @@ bool CvCaptureCAM_V4L::autosetup_capture_mode_v4l2()
palette = try_order[i]; palette = try_order[i];
if (try_palette_v4l2()) { if (try_palette_v4l2()) {
return true; return true;
} else if (errno == EBUSY) {
CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): device is busy");
closeDevice();
return false;
} }
} }
return false; return false;
...@@ -525,9 +588,15 @@ bool CvCaptureCAM_V4L::setFps(int value) ...@@ -525,9 +588,15 @@ bool CvCaptureCAM_V4L::setFps(int value)
streamparm.parm.capture.timeperframe.numerator = 1; streamparm.parm.capture.timeperframe.numerator = 1;
streamparm.parm.capture.timeperframe.denominator = __u32(value); streamparm.parm.capture.timeperframe.denominator = __u32(value);
if (!tryIoctl(VIDIOC_S_PARM, &streamparm) || !tryIoctl(VIDIOC_G_PARM, &streamparm)) if (!tryIoctl(VIDIOC_S_PARM, &streamparm) || !tryIoctl(VIDIOC_G_PARM, &streamparm))
{
CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): can't set FPS: " << value);
return false; return false;
}
fps = streamparm.parm.capture.timeperframe.denominator; CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): FPS="
<< streamparm.parm.capture.timeperframe.denominator << "/"
<< streamparm.parm.capture.timeperframe.numerator);
fps = streamparm.parm.capture.timeperframe.denominator; // TODO use numerator
return true; return true;
} }
...@@ -622,10 +691,9 @@ bool CvCaptureCAM_V4L::initCapture() ...@@ -622,10 +691,9 @@ bool CvCaptureCAM_V4L::initCapture()
if (!isOpened()) if (!isOpened())
return false; return false;
if (!try_init_v4l2()) { if (!try_init_v4l2())
#ifndef NDEBUG {
fprintf(stderr, " try_init_v4l2 open \"%s\": %s\n", deviceName.c_str(), strerror(errno)); CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): init failed: errno=" << errno << " (" << strerror(errno) << ")");
#endif
return false; return false;
} }
...@@ -633,14 +701,17 @@ bool CvCaptureCAM_V4L::initCapture() ...@@ -633,14 +701,17 @@ bool CvCaptureCAM_V4L::initCapture()
form = v4l2_format(); form = v4l2_format();
form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (!tryIoctl(VIDIOC_G_FMT, &form)) { if (!tryIoctl(VIDIOC_G_FMT, &form))
fprintf( stderr, "VIDEOIO ERROR: V4L2: Could not obtain specifics of capture window.\n"); {
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): Could not obtain specifics of capture window (VIDIOC_G_FMT): errno=" << errno << " (" << strerror(errno) << ")");
return false; return false;
} }
if (!autosetup_capture_mode_v4l2()) { if (!autosetup_capture_mode_v4l2())
if (errno != EBUSY) { {
fprintf(stderr, "VIDEOIO ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV\n"); if (errno != EBUSY)
{
CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): Pixel format of incoming image is unsupported by OpenCV");
} }
return false; return false;
} }
...@@ -682,16 +753,16 @@ bool CvCaptureCAM_V4L::requestBuffers() ...@@ -682,16 +753,16 @@ bool CvCaptureCAM_V4L::requestBuffers()
{ {
unsigned int buffer_number = bufferSize; unsigned int buffer_number = bufferSize;
while (buffer_number > 0) { while (buffer_number > 0) {
if (!requestBuffers(buffer_number)) if (requestBuffers(buffer_number) && req.count >= buffer_number)
return false; {
if (req.count >= buffer_number)
break; break;
}
buffer_number--; buffer_number--;
fprintf(stderr, "Insufficient buffer memory on %s -- decreasing buffers\n", deviceName.c_str()); CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): Insufficient buffer memory -- decreasing buffers: " << buffer_number);
} }
if (buffer_number < 1) { if (buffer_number < 1) {
fprintf(stderr, "Insufficient buffer memory on %s\n", deviceName.c_str()); CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): Insufficient buffer memory");
return false; return false;
} }
bufferSize = req.count; bufferSize = req.count;
...@@ -709,13 +780,18 @@ bool CvCaptureCAM_V4L::requestBuffers(unsigned int buffer_number) ...@@ -709,13 +780,18 @@ bool CvCaptureCAM_V4L::requestBuffers(unsigned int buffer_number)
req.memory = V4L2_MEMORY_MMAP; req.memory = V4L2_MEMORY_MMAP;
if (!tryIoctl(VIDIOC_REQBUFS, &req)) { if (!tryIoctl(VIDIOC_REQBUFS, &req)) {
if (EINVAL == errno) { int err = errno;
fprintf(stderr, "%s does not support memory mapping\n", deviceName.c_str()); if (EINVAL == err)
} else { {
perror("VIDIOC_REQBUFS"); CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): no support for memory mapping");
}
else
{
CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed VIDIOC_REQBUFS: errno=" << err << " (" << strerror(err) << ")");
} }
return false; return false;
} }
v4l_buffersRequested = true;
return true; return true;
} }
...@@ -729,7 +805,7 @@ bool CvCaptureCAM_V4L::createBuffers() ...@@ -729,7 +805,7 @@ bool CvCaptureCAM_V4L::createBuffers()
buf.index = n_buffers; buf.index = n_buffers;
if (!tryIoctl(VIDIOC_QUERYBUF, &buf)) { if (!tryIoctl(VIDIOC_QUERYBUF, &buf)) {
perror("VIDIOC_QUERYBUF"); CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed VIDIOC_QUERYBUF: errno=" << errno << " (" << strerror(errno) << ")");
return false; return false;
} }
...@@ -742,7 +818,7 @@ bool CvCaptureCAM_V4L::createBuffers() ...@@ -742,7 +818,7 @@ bool CvCaptureCAM_V4L::createBuffers()
deviceHandle, buf.m.offset); deviceHandle, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start) { if (MAP_FAILED == buffers[n_buffers].start) {
perror("mmap"); CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed mmap(" << buf.length << "): errno=" << errno << " (" << strerror(errno) << ")");
return false; return false;
} }
maxLength = maxLength > buf.length ? maxLength : buf.length; maxLength = maxLength > buf.length ? maxLength : buf.length;
...@@ -786,7 +862,7 @@ bool CvCaptureCAM_V4L::open(int _index) ...@@ -786,7 +862,7 @@ bool CvCaptureCAM_V4L::open(int _index)
} }
if (_index < 0) if (_index < 0)
{ {
fprintf(stderr, "VIDEOIO ERROR: V4L: can't find camera device\n"); CV_LOG_WARNING(NULL, "VIDEOIO(V4L2): can't find camera device");
name.clear(); name.clear();
return false; return false;
} }
...@@ -799,16 +875,15 @@ bool CvCaptureCAM_V4L::open(int _index) ...@@ -799,16 +875,15 @@ bool CvCaptureCAM_V4L::open(int _index)
bool res = open(name.c_str()); bool res = open(name.c_str());
if (!res) if (!res)
{ {
CV_LOG_WARNING(NULL, cv::format("VIDEOIO ERROR: V4L: can't open camera by index %d", _index)); CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): can't open camera by index");
} }
return res; return res;
} }
bool CvCaptureCAM_V4L::open(const char* _deviceName) bool CvCaptureCAM_V4L::open(const char* _deviceName)
{ {
#ifndef NDEBUG CV_Assert(_deviceName);
fprintf(stderr, "(DEBUG) V4L: opening %s\n", _deviceName); CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << _deviceName << "): opening...");
#endif
FirstCapture = true; FirstCapture = true;
width = DEFAULT_V4L_WIDTH; width = DEFAULT_V4L_WIDTH;
height = DEFAULT_V4L_HEIGHT; height = DEFAULT_V4L_HEIGHT;
...@@ -824,6 +899,7 @@ bool CvCaptureCAM_V4L::open(const char* _deviceName) ...@@ -824,6 +899,7 @@ bool CvCaptureCAM_V4L::open(const char* _deviceName)
bufferIndex = -1; bufferIndex = -1;
deviceHandle = ::open(deviceName.c_str(), O_RDWR /* required */ | O_NONBLOCK, 0); deviceHandle = ::open(deviceName.c_str(), O_RDWR /* required */ | O_NONBLOCK, 0);
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << _deviceName << "): deviceHandle=" << deviceHandle);
if (deviceHandle == -1) if (deviceHandle == -1)
return false; return false;
...@@ -837,7 +913,8 @@ bool CvCaptureCAM_V4L::read_frame_v4l2() ...@@ -837,7 +913,8 @@ bool CvCaptureCAM_V4L::read_frame_v4l2()
buf.memory = V4L2_MEMORY_MMAP; buf.memory = V4L2_MEMORY_MMAP;
while (!tryIoctl(VIDIOC_DQBUF, &buf)) { while (!tryIoctl(VIDIOC_DQBUF, &buf)) {
if (errno == EIO && !(buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) { int err = errno;
if (err == EIO && !(buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) {
// Maybe buffer not in the queue? Try to put there // Maybe buffer not in the queue? Try to put there
if (!tryIoctl(VIDIOC_QBUF, &buf)) if (!tryIoctl(VIDIOC_QBUF, &buf))
return false; return false;
...@@ -845,7 +922,7 @@ bool CvCaptureCAM_V4L::read_frame_v4l2() ...@@ -845,7 +922,7 @@ bool CvCaptureCAM_V4L::read_frame_v4l2()
} }
/* display the error and stop processing */ /* display the error and stop processing */
returnFrame = false; returnFrame = false;
perror("VIDIOC_DQBUF"); CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): can't read frame (VIDIOC_DQBUF): errno=" << err << " (" << strerror(err) << ")");
return false; return false;
} }
...@@ -863,37 +940,64 @@ bool CvCaptureCAM_V4L::read_frame_v4l2() ...@@ -863,37 +940,64 @@ bool CvCaptureCAM_V4L::read_frame_v4l2()
bool CvCaptureCAM_V4L::tryIoctl(unsigned long ioctlCode, void *parameter, bool failIfBusy, int attempts) const bool CvCaptureCAM_V4L::tryIoctl(unsigned long ioctlCode, void *parameter, bool failIfBusy, int attempts) const
{ {
if (attempts == 0) { CV_Assert(attempts > 0);
return false; CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): tryIoctl(" << deviceHandle << ", "
} << decode_ioctl_code(ioctlCode) << "(" << ioctlCode << "), failIfBusy=" << failIfBusy << ")"
while (-1 == ioctl(deviceHandle, ioctlCode, parameter)) { );
const bool isBusy = (errno == EBUSY); while (true)
if (isBusy & failIfBusy) { {
errno = 0;
int result = ioctl(deviceHandle, ioctlCode, parameter);
int err = errno;
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): call ioctl(" << deviceHandle << ", "
<< decode_ioctl_code(ioctlCode) << "(" << ioctlCode << "), ...) => "
<< result << " errno=" << err << " (" << strerror(err) << ")"
);
if (result != -1)
return true; // success
const bool isBusy = (err == EBUSY);
if (isBusy && failIfBusy)
{
CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): ioctl returns with errno=EBUSY");
return false; return false;
} }
if ((attempts > 0) && (--attempts == 0)) { if (!(isBusy || errno == EAGAIN))
return false; return false;
}
if (!(isBusy || errno == EAGAIN)) if (--attempts == 0) {
return false; return false;
}
fd_set fds; fd_set fds;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(deviceHandle, &fds); FD_SET(deviceHandle, &fds);
/* Timeout. */ /* Timeout. */
static int param_v4l_select_timeout = (int)utils::getConfigurationParameterSizeT("OPENCV_VIDEOIO_V4L_SELECT_TIMEOUT", 10);
struct timeval tv; struct timeval tv;
tv.tv_sec = 10; tv.tv_sec = param_v4l_select_timeout;
tv.tv_usec = 0; tv.tv_usec = 0;
int result = select(deviceHandle + 1, &fds, NULL, NULL, &tv); errno = 0;
if (0 == result) { result = select(deviceHandle + 1, &fds, NULL, NULL, &tv);
fprintf(stderr, "select timeout\n"); err = errno;
if (0 == result)
{
CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): select() timeout.");
return false;
}
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): select(" << deviceHandle << ") => "
<< result << " errno = " << err << " (" << strerror(err) << ")"
);
if (EINTR == err) // don't loop if signal occurred, like Ctrl+C
{
return false; return false;
} }
if (-1 == result && EINTR != errno)
perror("select");
} }
return true; return true;
} }
...@@ -914,14 +1018,12 @@ bool CvCaptureCAM_V4L::grabFrame() ...@@ -914,14 +1018,12 @@ bool CvCaptureCAM_V4L::grabFrame()
buf.index = index; buf.index = index;
if (!tryIoctl(VIDIOC_QBUF, &buf)) { if (!tryIoctl(VIDIOC_QBUF, &buf)) {
perror("VIDIOC_QBUF"); CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed VIDIOC_QBUF (buffer=" << index << "): errno=" << errno << " (" << strerror(errno) << ")");
return false; return false;
} }
} }
if(!streaming(true)) { if (!streaming(true)) {
/* error enabling the stream */
perror("VIDIOC_STREAMON");
return false; return false;
} }
...@@ -936,9 +1038,12 @@ bool CvCaptureCAM_V4L::grabFrame() ...@@ -936,9 +1038,12 @@ bool CvCaptureCAM_V4L::grabFrame()
FirstCapture = false; FirstCapture = false;
} }
// In the case that the grab frame was without retrieveFrame // In the case that the grab frame was without retrieveFrame
if (bufferIndex >= 0) { if (bufferIndex >= 0)
{
if (!tryIoctl(VIDIOC_QBUF, &buffers[bufferIndex].buffer)) if (!tryIoctl(VIDIOC_QBUF, &buffers[bufferIndex].buffer))
perror("VIDIOC_QBUF"); {
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed VIDIOC_QBUF (buffer=" << bufferIndex << "): errno=" << errno << " (" << strerror(errno) << ")");
}
} }
return read_frame_v4l2(); return read_frame_v4l2();
} }
...@@ -1453,6 +1558,7 @@ void CvCaptureCAM_V4L::convertToRgb(const Buffer &currentBuffer) ...@@ -1453,6 +1558,7 @@ void CvCaptureCAM_V4L::convertToRgb(const Buffer &currentBuffer)
#ifdef HAVE_JPEG #ifdef HAVE_JPEG
case V4L2_PIX_FMT_MJPEG: case V4L2_PIX_FMT_MJPEG:
case V4L2_PIX_FMT_JPEG: case V4L2_PIX_FMT_JPEG:
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): decoding JPEG frame: size=" << currentBuffer.buffer.bytesused);
cv::imdecode(Mat(1, currentBuffer.buffer.bytesused, CV_8U, currentBuffer.start), IMREAD_COLOR, &destination); cv::imdecode(Mat(1, currentBuffer.buffer.bytesused, CV_8U, currentBuffer.start), IMREAD_COLOR, &destination);
return; return;
#endif #endif
...@@ -1695,7 +1801,7 @@ bool CvCaptureCAM_V4L::controlInfo(int property_id, __u32 &_v4l2id, cv::Range &r ...@@ -1695,7 +1801,7 @@ bool CvCaptureCAM_V4L::controlInfo(int property_id, __u32 &_v4l2id, cv::Range &r
v4l2_queryctrl queryctrl = v4l2_queryctrl(); v4l2_queryctrl queryctrl = v4l2_queryctrl();
queryctrl.id = __u32(v4l2id); queryctrl.id = __u32(v4l2id);
if (v4l2id == -1 || !tryIoctl(VIDIOC_QUERYCTRL, &queryctrl)) { if (v4l2id == -1 || !tryIoctl(VIDIOC_QUERYCTRL, &queryctrl)) {
fprintf(stderr, "VIDEOIO ERROR: V4L2: property %s is not supported\n", capPropertyName(property_id).c_str()); CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): property " << capPropertyName(property_id) << " is not supported");
return false; return false;
} }
_v4l2id = __u32(v4l2id); _v4l2id = __u32(v4l2id);
...@@ -1726,7 +1832,9 @@ bool CvCaptureCAM_V4L::icvControl(__u32 v4l2id, int &value, bool isSet) const ...@@ -1726,7 +1832,9 @@ bool CvCaptureCAM_V4L::icvControl(__u32 v4l2id, int &value, bool isSet) const
/* The driver may clamp the value or return ERANGE, ignored here */ /* The driver may clamp the value or return ERANGE, ignored here */
if (!tryIoctl(isSet ? VIDIOC_S_CTRL : VIDIOC_G_CTRL, &control)) { if (!tryIoctl(isSet ? VIDIOC_S_CTRL : VIDIOC_G_CTRL, &control)) {
switch (errno) { int err = errno;
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed " << (isSet ? "VIDIOC_S_CTRL" : "VIDIOC_G_CTRL") << ": errno=" << err << " (" << strerror(err) << ")");
switch (err) {
#ifndef NDEBUG #ifndef NDEBUG
case EINVAL: case EINVAL:
fprintf(stderr, fprintf(stderr,
...@@ -1741,7 +1849,6 @@ bool CvCaptureCAM_V4L::icvControl(__u32 v4l2id, int &value, bool isSet) const ...@@ -1741,7 +1849,6 @@ bool CvCaptureCAM_V4L::icvControl(__u32 v4l2id, int &value, bool isSet) const
break; break;
#endif #endif
default: default:
perror(isSet ? "VIDIOC_S_CTRL" : "VIDIOC_G_CTRL");
break; break;
} }
return false; return false;
...@@ -1775,7 +1882,7 @@ double CvCaptureCAM_V4L::getProperty(int property_id) const ...@@ -1775,7 +1882,7 @@ double CvCaptureCAM_V4L::getProperty(int property_id) const
v4l2_streamparm sp = v4l2_streamparm(); v4l2_streamparm sp = v4l2_streamparm();
sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (!tryIoctl(VIDIOC_G_PARM, &sp)) { if (!tryIoctl(VIDIOC_G_PARM, &sp)) {
fprintf(stderr, "VIDEOIO ERROR: V4L: Unable to get camera FPS\n"); CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): Unable to get camera FPS");
return -1; return -1;
} }
return sp.parm.capture.timeperframe.denominator / (double)sp.parm.capture.timeperframe.numerator; return sp.parm.capture.timeperframe.denominator / (double)sp.parm.capture.timeperframe.numerator;
...@@ -1865,7 +1972,7 @@ bool CvCaptureCAM_V4L::setProperty( int property_id, double _value ) ...@@ -1865,7 +1972,7 @@ bool CvCaptureCAM_V4L::setProperty( int property_id, double _value )
return true; return true;
if (value > MAX_V4L_BUFFERS || value < 1) { if (value > MAX_V4L_BUFFERS || value < 1) {
fprintf(stderr, "V4L: Bad buffer size %d, buffer size must be from 1 to %d\n", value, MAX_V4L_BUFFERS); CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): Bad buffer size " << value << ", buffer size must be from 1 to " << MAX_V4L_BUFFERS);
return false; return false;
} }
bufferSize = value; bufferSize = value;
...@@ -1921,13 +2028,15 @@ void CvCaptureCAM_V4L::releaseBuffers() ...@@ -1921,13 +2028,15 @@ void CvCaptureCAM_V4L::releaseBuffers()
bufferIndex = -1; bufferIndex = -1;
FirstCapture = true; FirstCapture = true;
if (!isOpened())
if (!v4l_buffersRequested)
return; return;
v4l_buffersRequested = false;
for (unsigned int n_buffers = 0; n_buffers < MAX_V4L_BUFFERS; ++n_buffers) { for (unsigned int n_buffers = 0; n_buffers < MAX_V4L_BUFFERS; ++n_buffers) {
if (buffers[n_buffers].start) { if (buffers[n_buffers].start) {
if (-1 == munmap(buffers[n_buffers].start, buffers[n_buffers].length)) { if (-1 == munmap(buffers[n_buffers].start, buffers[n_buffers].length)) {
perror("munmap"); CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed munmap(): errno=" << errno << " (" << strerror(errno) << ")");
} else { } else {
buffers[n_buffers].start = 0; buffers[n_buffers].start = 0;
} }
...@@ -1941,11 +2050,28 @@ void CvCaptureCAM_V4L::releaseBuffers() ...@@ -1941,11 +2050,28 @@ void CvCaptureCAM_V4L::releaseBuffers()
bool CvCaptureCAM_V4L::streaming(bool startStream) bool CvCaptureCAM_V4L::streaming(bool startStream)
{ {
if (!isOpened()) if (startStream != v4l_streamStarted)
return !startStream; {
if (!isOpened())
{
CV_Assert(v4l_streamStarted == false);
return !startStream;
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE; type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
return tryIoctl(startStream ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &type); bool result = tryIoctl(startStream ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &type);
if (result)
{
v4l_streamStarted = startStream;
return true;
}
if (startStream)
{
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed VIDIOC_STREAMON: errno=" << errno << " (" << strerror(errno) << ")");
}
return false;
}
return startStream;
} }
IplImage *CvCaptureCAM_V4L::retrieveFrame(int) IplImage *CvCaptureCAM_V4L::retrieveFrame(int)
...@@ -1963,6 +2089,7 @@ IplImage *CvCaptureCAM_V4L::retrieveFrame(int) ...@@ -1963,6 +2089,7 @@ IplImage *CvCaptureCAM_V4L::retrieveFrame(int)
} else { } else {
// for mjpeg streams the size might change in between, so we have to change the header // for mjpeg streams the size might change in between, so we have to change the header
// We didn't allocate memory when not convert_rgb, but we have to recreate the header // We didn't allocate memory when not convert_rgb, but we have to recreate the header
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): buffer input size=" << currentBuffer.buffer.bytesused);
if (frame.imageSize != (int)currentBuffer.buffer.bytesused) if (frame.imageSize != (int)currentBuffer.buffer.bytesused)
v4l2_create_frame(); v4l2_create_frame();
...@@ -1972,7 +2099,9 @@ IplImage *CvCaptureCAM_V4L::retrieveFrame(int) ...@@ -1972,7 +2099,9 @@ IplImage *CvCaptureCAM_V4L::retrieveFrame(int)
} }
//Revert buffer to the queue //Revert buffer to the queue
if (!tryIoctl(VIDIOC_QBUF, &buffers[bufferIndex].buffer)) if (!tryIoctl(VIDIOC_QBUF, &buffers[bufferIndex].buffer))
perror("VIDIOC_QBUF"); {
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed VIDIOC_QBUF: errno=" << errno << " (" << strerror(errno) << ")");
}
bufferIndex = -1; bufferIndex = -1;
return &frame; return &frame;
......
...@@ -48,6 +48,12 @@ ...@@ -48,6 +48,12 @@
#include "opencv2/core/private.hpp" #include "opencv2/core/private.hpp"
#include <opencv2/core/utils/configuration.private.hpp> #include <opencv2/core/utils/configuration.private.hpp>
#include <opencv2/core/utils/logger.defines.hpp>
#ifdef NDEBUG
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG + 1
#else
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_VERBOSE + 1
#endif
#include <opencv2/core/utils/logger.hpp> #include <opencv2/core/utils/logger.hpp>
#include "opencv2/imgcodecs.hpp" #include "opencv2/imgcodecs.hpp"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment