#define MAX_V4L_BUFFERS 10
#define DEFAULT_V4L_BUFFERS 4
+// types of memory in 'special' buffer
+enum {
+ MEMORY_ORIG = 0, // Image data in original format.
+ MEMORY_RGB = 1, // Image data converted to RGB format.
+};
+
// if enabled, then bad JPEG warnings become errors and cause NULL returned instead of image
#define V4L_ABORT_BADJPEG
return "unknown";
}
+struct Memory
+{
+ void * start;
+ size_t length;
+
+ Memory() : start(NULL), length(0) {}
+};
+
/* Device Capture Objects */
/* V4L2 structure */
struct Buffer
{
- void * start;
- size_t length;
+ Memory memories[VIDEO_MAX_PLANES];
+ v4l2_plane planes[VIDEO_MAX_PLANES] = {};
+ // Total number of bytes occupied by data in the all planes (payload)
+ __u32 bytesused;
// This is dequeued buffer. It used for to put it back in the queue.
// The buffer is valid only if capture->bufferIndex >= 0
v4l2_buffer buffer;
- Buffer() : start(NULL), length(0)
+ Buffer()
{
buffer = v4l2_buffer();
}
v4l2_format form;
v4l2_requestbuffers req;
v4l2_buf_type type;
+ unsigned char num_planes;
timeval timestamp;
fps(0), convert_rgb(0), frame_allocated(false), returnFrame(false),
channelNumber(-1), normalizePropRange(false),
type(V4L2_BUF_TYPE_VIDEO_CAPTURE),
+ num_planes(0),
havePendingFrame(false)
{
frame = cvIplImage();
bool CvCaptureCAM_V4L::try_palette_v4l2()
{
form = v4l2_format();
- form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- form.fmt.pix.pixelformat = palette;
- form.fmt.pix.field = V4L2_FIELD_ANY;
- form.fmt.pix.width = width;
- form.fmt.pix.height = height;
+ form.type = type;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ form.fmt.pix_mp.pixelformat = palette;
+ form.fmt.pix_mp.field = V4L2_FIELD_ANY;
+ form.fmt.pix_mp.width = width;
+ form.fmt.pix_mp.height = height;
+ } else {
+ form.fmt.pix.pixelformat = palette;
+ form.fmt.pix.field = V4L2_FIELD_ANY;
+ form.fmt.pix.width = width;
+ form.fmt.pix.height = height;
+ }
if (!tryIoctl(VIDIOC_S_FMT, &form, true))
{
return false;
}
+ if (V4L2_TYPE_IS_MULTIPLANAR(type))
+ return palette == form.fmt.pix_mp.pixelformat;
return palette == form.fmt.pix.pixelformat;
}
return false;
}
- if ((capability.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0)
+ if ((capability.capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) == 0)
{
/* Nope. */
- CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): not supported - device is unable to capture video (missing V4L2_CAP_VIDEO_CAPTURE)");
+ CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): not supported - device is unable to capture video (missing V4L2_CAP_VIDEO_CAPTURE or V4L2_CAP_VIDEO_CAPTURE_MPLANE)");
return false;
}
+
+ if (capability.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
return true;
}
return false;
v4l2_streamparm streamparm = v4l2_streamparm();
- streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ streamparm.type = type;
streamparm.parm.capture.timeperframe.numerator = 1;
streamparm.parm.capture.timeperframe.denominator = __u32(value);
if (!tryIoctl(VIDIOC_S_PARM, &streamparm) || !tryIoctl(VIDIOC_G_PARM, &streamparm))
void CvCaptureCAM_V4L::v4l2_create_frame()
{
- CV_Assert(form.fmt.pix.width <= (uint)std::numeric_limits<int>::max());
- CV_Assert(form.fmt.pix.height <= (uint)std::numeric_limits<int>::max());
- CvSize size = {(int)form.fmt.pix.width, (int)form.fmt.pix.height};
+ CvSize size;
int channels = 3;
int depth = IPL_DEPTH_8U;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ CV_Assert(form.fmt.pix_mp.width <= (uint)std::numeric_limits<int>::max());
+ CV_Assert(form.fmt.pix_mp.height <= (uint)std::numeric_limits<int>::max());
+ size = {(int)form.fmt.pix_mp.width, (int)form.fmt.pix_mp.height};
+ } else {
+ CV_Assert(form.fmt.pix.width <= (uint)std::numeric_limits<int>::max());
+ CV_Assert(form.fmt.pix.height <= (uint)std::numeric_limits<int>::max());
+ size = {(int)form.fmt.pix.width, (int)form.fmt.pix.height};
+ }
+
if (!convert_rgb) {
switch (palette) {
case V4L2_PIX_FMT_BGR24:
default:
channels = 1;
if(bufferIndex < 0)
- size = cvSize(buffers[MAX_V4L_BUFFERS].length, 1);
- else
- size = cvSize(buffers[bufferIndex].buffer.bytesused, 1);
+ size = cvSize(buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].length, 1);
+ else {
+ __u32 bytesused = 0;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ __u32 data_offset;
+ for (unsigned char n_planes = 0; n_planes < num_planes; n_planes++) {
+ data_offset = buffers[bufferIndex].planes[n_planes].data_offset;
+ bytesused += buffers[bufferIndex].planes[n_planes].bytesused - data_offset;
+ }
+ } else
+ bytesused = buffers[bufferIndex].buffer.bytesused;
+ size = cvSize(bytesused, 1);
+ }
break;
}
}
/* Find Window info */
form = v4l2_format();
- form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ form.type = type;
if (!tryIoctl(VIDIOC_G_FMT, &form))
{
/* try to set framerate */
setFps(fps);
- unsigned int min;
-
/* Buggy driver paranoia. */
- min = form.fmt.pix.width * 2;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ // TODO: add size adjustment if needed
+ } else {
+ unsigned int min;
+
+ min = form.fmt.pix.width * 2;
- if (form.fmt.pix.bytesperline < min)
- form.fmt.pix.bytesperline = min;
+ if (form.fmt.pix.bytesperline < min)
+ form.fmt.pix.bytesperline = min;
- min = form.fmt.pix.bytesperline * form.fmt.pix.height;
+ min = form.fmt.pix.bytesperline * form.fmt.pix.height;
- if (form.fmt.pix.sizeimage < min)
- form.fmt.pix.sizeimage = min;
+ if (form.fmt.pix.sizeimage < min)
+ form.fmt.pix.sizeimage = min;
+ }
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(type))
+ num_planes = form.fmt.pix_mp.num_planes;
+ else
+ num_planes = 1;
if (!requestBuffers())
return false;
req = v4l2_requestbuffers();
req.count = buffer_number;
- req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.type = type;
req.memory = V4L2_MEMORY_MMAP;
if (!tryIoctl(VIDIOC_REQBUFS, &req)) {
size_t maxLength = 0;
for (unsigned int n_buffers = 0; n_buffers < req.count; ++n_buffers) {
v4l2_buffer buf = v4l2_buffer();
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_plane mplanes[VIDEO_MAX_PLANES];
+ size_t length;
+ off_t offset;
+ buf.type = type;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ buf.m.planes = mplanes;
+ buf.length = VIDEO_MAX_PLANES;
+ }
if (!tryIoctl(VIDIOC_QUERYBUF, &buf)) {
CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed VIDIOC_QUERYBUF: errno=" << errno << " (" << strerror(errno) << ")");
return false;
}
- buffers[n_buffers].length = buf.length;
- buffers[n_buffers].start =
- mmap(NULL /* start anywhere */,
- buf.length,
- PROT_READ /* required */,
- MAP_SHARED /* recommended */,
- deviceHandle, buf.m.offset);
+ CV_Assert(1 <= num_planes && num_planes <= VIDEO_MAX_PLANES);
+ for (unsigned char n_planes = 0; n_planes < num_planes; n_planes++) {
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ length = buf.m.planes[n_planes].length;
+ offset = buf.m.planes[n_planes].m.mem_offset;
+ } else {
+ length = buf.length;
+ offset = buf.m.offset;
+ }
- if (MAP_FAILED == buffers[n_buffers].start) {
- CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed mmap(" << buf.length << "): errno=" << errno << " (" << strerror(errno) << ")");
- return false;
+ buffers[n_buffers].memories[n_planes].length = length;
+ buffers[n_buffers].memories[n_planes].start =
+ mmap(NULL /* start anywhere */,
+ length,
+ PROT_READ /* required */,
+ MAP_SHARED /* recommended */,
+ deviceHandle, offset);
+ if (MAP_FAILED == buffers[n_buffers].memories[n_planes].start) {
+ CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed mmap(" << length << "): errno=" << errno << " (" << strerror(errno) << ")");
+ return false;
+ }
}
- maxLength = maxLength > buf.length ? maxLength : buf.length;
+
+ maxLength = maxLength > length ? maxLength : length;
}
if (maxLength > 0) {
- buffers[MAX_V4L_BUFFERS].start = malloc(maxLength);
- buffers[MAX_V4L_BUFFERS].length = maxLength;
- }
- return buffers[MAX_V4L_BUFFERS].start != 0;
+ maxLength *= num_planes;
+ buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start = malloc(maxLength);
+ buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].length = maxLength;
+ buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start = malloc(maxLength);
+ buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].length = maxLength;
+ }
+ return (buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start != 0) &&
+ (buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start != 0);
}
/**
bool CvCaptureCAM_V4L::read_frame_v4l2()
{
v4l2_buffer buf = v4l2_buffer();
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_plane mplanes[VIDEO_MAX_PLANES];
+ buf.type = type;
buf.memory = V4L2_MEMORY_MMAP;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ buf.m.planes = mplanes;
+ buf.length = VIDEO_MAX_PLANES;
+ }
while (!tryIoctl(VIDIOC_DQBUF, &buf)) {
int err = errno;
}
CV_Assert(buf.index < req.count);
- CV_Assert(buffers[buf.index].length == buf.length);
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ for (unsigned char n_planes = 0; n_planes < num_planes; n_planes++)
+ CV_Assert(buffers[buf.index].memories[n_planes].length == buf.m.planes[n_planes].length);
+ } else
+ CV_Assert(buffers[buf.index].memories[MEMORY_ORIG].length == buf.length);
//We shouldn't use this buffer in the queue while not retrieve frame from it.
buffers[buf.index].buffer = buf;
bufferIndex = buf.index;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ __u32 offset = 0;
+
+ buffers[buf.index].buffer.m.planes = buffers[buf.index].planes;
+ memcpy(buffers[buf.index].planes, buf.m.planes, sizeof(mplanes));
+
+ for (unsigned char n_planes = 0; n_planes < num_planes; n_planes++) {
+ __u32 bytesused;
+ bytesused = buffers[buf.index].planes[n_planes].bytesused -
+ buffers[buf.index].planes[n_planes].data_offset;
+ offset += bytesused;
+ }
+ buffers[buf.index].bytesused = offset;
+ } else
+ buffers[buf.index].bytesused = buffers[buf.index].buffer.bytesused;
+
//set timestamp in capture struct to be timestamp of most recent frame
timestamp = buf.timestamp;
return true;
bufferIndex = -1;
for (__u32 index = 0; index < req.count; ++index) {
v4l2_buffer buf = v4l2_buffer();
+ v4l2_plane mplanes[VIDEO_MAX_PLANES];
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.type = type;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = index;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ buf.m.planes = mplanes;
+ buf.length = VIDEO_MAX_PLANES;
+ }
if (!tryIoctl(VIDIOC_QBUF, &buf)) {
CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed VIDIOC_QBUF (buffer=" << index << "): errno=" << errno << " (" << strerror(errno) << ")");
void CvCaptureCAM_V4L::convertToRgb(const Buffer ¤tBuffer)
{
- cv::Size imageSize(form.fmt.pix.width, form.fmt.pix.height);
+ cv::Size imageSize;
+ unsigned char *start;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ __u32 offset = 0;
+ start = (unsigned char*)buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start;
+ for (unsigned char n_planes = 0; n_planes < num_planes; n_planes++) {
+ __u32 data_offset, bytesused;
+ data_offset = currentBuffer.planes[n_planes].data_offset;
+ bytesused = currentBuffer.planes[n_planes].bytesused - data_offset;
+ memcpy(start + offset, (char *)currentBuffer.memories[n_planes].start + data_offset,
+ std::min(currentBuffer.memories[n_planes].length, (size_t)bytesused));
+ offset += bytesused;
+ }
+
+ imageSize = cv::Size(form.fmt.pix_mp.width, form.fmt.pix_mp.height);
+ } else {
+ start = (unsigned char*)currentBuffer.memories[MEMORY_ORIG].start;
+
+ imageSize = cv::Size(form.fmt.pix.width, form.fmt.pix.height);
+ }
// Not found conversion
switch (palette)
{
case V4L2_PIX_FMT_YUV411P:
yuv411p_to_rgb24(imageSize.width, imageSize.height,
- (unsigned char*)(currentBuffer.start),
- (unsigned char*)frame.imageData);
+ start, (unsigned char*)frame.imageData);
return;
case V4L2_PIX_FMT_SBGGR8:
bayer2rgb24(imageSize.width, imageSize.height,
- (unsigned char*)currentBuffer.start,
- (unsigned char*)frame.imageData);
+ start, (unsigned char*)frame.imageData);
return;
case V4L2_PIX_FMT_SN9C10X:
sonix_decompress_init();
sonix_decompress(imageSize.width, imageSize.height,
- (unsigned char*)currentBuffer.start,
- (unsigned char*)buffers[MAX_V4L_BUFFERS].start);
+ start, (unsigned char*)buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start);
bayer2rgb24(imageSize.width, imageSize.height,
- (unsigned char*)buffers[MAX_V4L_BUFFERS].start,
+ (unsigned char*)buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start,
(unsigned char*)frame.imageData);
return;
case V4L2_PIX_FMT_SGBRG8:
sgbrg2rgb24(imageSize.width, imageSize.height,
- (unsigned char*)currentBuffer.start,
- (unsigned char*)frame.imageData);
+ start, (unsigned char*)frame.imageData);
return;
default:
break;
cv::Mat destination(imageSize, CV_8UC3, frame.imageData);
switch (palette) {
case V4L2_PIX_FMT_YVU420:
- cv::cvtColor(cv::Mat(imageSize.height * 3 / 2, imageSize.width, CV_8U, currentBuffer.start), destination,
+ cv::cvtColor(cv::Mat(imageSize.height * 3 / 2, imageSize.width, CV_8U, start), destination,
COLOR_YUV2BGR_YV12);
return;
case V4L2_PIX_FMT_YUV420:
- cv::cvtColor(cv::Mat(imageSize.height * 3 / 2, imageSize.width, CV_8U, currentBuffer.start), destination,
+ cv::cvtColor(cv::Mat(imageSize.height * 3 / 2, imageSize.width, CV_8U, start), destination,
COLOR_YUV2BGR_IYUV);
return;
case V4L2_PIX_FMT_NV12:
- cv::cvtColor(cv::Mat(imageSize.height * 3 / 2, imageSize.width, CV_8U, currentBuffer.start), destination,
+ cv::cvtColor(cv::Mat(imageSize.height * 3 / 2, imageSize.width, CV_8U, start), destination,
COLOR_YUV2RGB_NV12);
return;
case V4L2_PIX_FMT_NV21:
- cv::cvtColor(cv::Mat(imageSize.height * 3 / 2, imageSize.width, CV_8U, currentBuffer.start), destination,
+ cv::cvtColor(cv::Mat(imageSize.height * 3 / 2, imageSize.width, CV_8U, start), destination,
COLOR_YUV2RGB_NV21);
return;
#ifdef HAVE_JPEG
case V4L2_PIX_FMT_MJPEG:
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_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): decoding JPEG frame: size=" << currentBuffer.bytesused);
+ cv::imdecode(Mat(1, currentBuffer.bytesused, CV_8U, start), IMREAD_COLOR, &destination);
return;
#endif
case V4L2_PIX_FMT_YUYV:
- cv::cvtColor(cv::Mat(imageSize, CV_8UC2, currentBuffer.start), destination, COLOR_YUV2BGR_YUYV);
+ cv::cvtColor(cv::Mat(imageSize, CV_8UC2, start), destination, COLOR_YUV2BGR_YUYV);
return;
case V4L2_PIX_FMT_UYVY:
- cv::cvtColor(cv::Mat(imageSize, CV_8UC2, currentBuffer.start), destination, COLOR_YUV2BGR_UYVY);
+ cv::cvtColor(cv::Mat(imageSize, CV_8UC2, start), destination, COLOR_YUV2BGR_UYVY);
return;
case V4L2_PIX_FMT_RGB24:
- cv::cvtColor(cv::Mat(imageSize, CV_8UC3, currentBuffer.start), destination, COLOR_RGB2BGR);
+ cv::cvtColor(cv::Mat(imageSize, CV_8UC3, start), destination, COLOR_RGB2BGR);
return;
case V4L2_PIX_FMT_Y16:
{
- cv::Mat temp(imageSize, CV_8UC1, buffers[MAX_V4L_BUFFERS].start);
- cv::Mat(imageSize, CV_16UC1, currentBuffer.start).convertTo(temp, CV_8U, 1.0 / 256);
+ cv::Mat temp(imageSize, CV_8UC1, buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start);
+ cv::Mat(imageSize, CV_16UC1, start).convertTo(temp, CV_8U, 1.0 / 256);
cv::cvtColor(temp, destination, COLOR_GRAY2BGR);
return;
}
case V4L2_PIX_FMT_Y12:
{
- cv::Mat temp(imageSize, CV_8UC1, buffers[MAX_V4L_BUFFERS].start);
- cv::Mat(imageSize, CV_16UC1, currentBuffer.start).convertTo(temp, CV_8U, 1.0 / 16);
+ cv::Mat temp(imageSize, CV_8UC1, buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start);
+ cv::Mat(imageSize, CV_16UC1, start).convertTo(temp, CV_8U, 1.0 / 16);
cv::cvtColor(temp, destination, COLOR_GRAY2BGR);
return;
}
case V4L2_PIX_FMT_Y10:
{
- cv::Mat temp(imageSize, CV_8UC1, buffers[MAX_V4L_BUFFERS].start);
- cv::Mat(imageSize, CV_16UC1, currentBuffer.start).convertTo(temp, CV_8U, 1.0 / 4);
+ cv::Mat temp(imageSize, CV_8UC1, buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start);
+ cv::Mat(imageSize, CV_16UC1, start).convertTo(temp, CV_8U, 1.0 / 4);
cv::cvtColor(temp, destination, COLOR_GRAY2BGR);
return;
}
case V4L2_PIX_FMT_GREY:
- cv::cvtColor(cv::Mat(imageSize, CV_8UC1, currentBuffer.start), destination, COLOR_GRAY2BGR);
+ cv::cvtColor(cv::Mat(imageSize, CV_8UC1, start), destination, COLOR_GRAY2BGR);
break;
case V4L2_PIX_FMT_XBGR32:
case V4L2_PIX_FMT_ABGR32:
- cv::cvtColor(cv::Mat(imageSize, CV_8UC4, currentBuffer.start), destination, COLOR_BGRA2BGR);
+ cv::cvtColor(cv::Mat(imageSize, CV_8UC4, start), destination, COLOR_BGRA2BGR);
break;
case V4L2_PIX_FMT_BGR24:
default:
- memcpy((char *)frame.imageData, (char *)currentBuffer.start,
- std::min(frame.imageSize, (int)currentBuffer.buffer.bytesused));
+ memcpy((char *)frame.imageData, start,
+ std::min(frame.imageSize, (int)currentBuffer.bytesused));
break;
}
}
{
switch (property_id) {
case cv::CAP_PROP_FRAME_WIDTH:
- return form.fmt.pix.width;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type))
+ return form.fmt.pix_mp.width;
+ else
+ return form.fmt.pix.width;
case cv::CAP_PROP_FRAME_HEIGHT:
- return form.fmt.pix.height;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type))
+ return form.fmt.pix_mp.height;
+ else
+ return form.fmt.pix.height;
case cv::CAP_PROP_FOURCC:
return palette;
case cv::CAP_PROP_FORMAT:
case cv::CAP_PROP_FPS:
{
v4l2_streamparm sp = v4l2_streamparm();
- sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ sp.type = type;
if (!tryIoctl(VIDIOC_G_PARM, &sp)) {
CV_LOG_WARNING(NULL, "VIDEOIO(V4L2:" << deviceName << "): Unable to get camera FPS");
return -1;
{
releaseFrame();
- if (buffers[MAX_V4L_BUFFERS].start) {
- free(buffers[MAX_V4L_BUFFERS].start);
- buffers[MAX_V4L_BUFFERS].start = 0;
+ if (buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start) {
+ free(buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start);
+ buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start = 0;
+ }
+
+ if (buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start) {
+ free(buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start);
+ buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start = 0;
}
bufferIndex = -1;
v4l_buffersRequested = false;
for (unsigned int n_buffers = 0; n_buffers < MAX_V4L_BUFFERS; ++n_buffers) {
- if (buffers[n_buffers].start) {
- if (-1 == munmap(buffers[n_buffers].start, buffers[n_buffers].length)) {
- CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed munmap(): errno=" << errno << " (" << strerror(errno) << ")");
- } else {
- buffers[n_buffers].start = 0;
+ for (unsigned char n_planes = 0; n_planes < num_planes; n_planes++) {
+ if (buffers[n_buffers].memories[n_planes].start) {
+ if (-1 == munmap(buffers[n_buffers].memories[n_planes].start,
+ buffers[n_buffers].memories[n_planes].length)) {
+ CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): failed munmap(): errno=" << errno << " (" << strerror(errno) << ")");
+ } else {
+ buffers[n_buffers].memories[n_planes].start = 0;
+ }
}
}
}
return !startStream;
}
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
bool result = tryIoctl(startStream ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &type);
if (result)
{
} else {
// 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
- CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): buffer input size=" << currentBuffer.buffer.bytesused);
- if (frame.imageSize != (int)currentBuffer.buffer.bytesused)
+ CV_LOG_DEBUG(NULL, "VIDEOIO(V4L2:" << deviceName << "): buffer input size=" << currentBuffer.bytesused);
+ if (frame.imageSize != (int)currentBuffer.bytesused)
v4l2_create_frame();
- frame.imageData = (char *)buffers[MAX_V4L_BUFFERS].start;
- memcpy(buffers[MAX_V4L_BUFFERS].start, currentBuffer.start,
- std::min(buffers[MAX_V4L_BUFFERS].length, (size_t)currentBuffer.buffer.bytesused));
+ frame.imageData = (char *)buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start;
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ __u32 offset = 0;
+ for (unsigned char n_planes = 0; n_planes < num_planes; n_planes++) {
+ __u32 data_offset, bytesused;
+ data_offset = currentBuffer.planes[n_planes].data_offset;
+ bytesused = currentBuffer.planes[n_planes].bytesused - data_offset;
+ memcpy((unsigned char*)buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start + offset,
+ (char *)currentBuffer.memories[n_planes].start + data_offset,
+ std::min(currentBuffer.memories[n_planes].length, (size_t)bytesused));
+ offset += bytesused;
+ }
+ } else {
+ memcpy(buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start, currentBuffer.memories[MEMORY_ORIG].start,
+ std::min(buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].length, (size_t)currentBuffer.buffer.bytesused));
+ }
}
//Revert buffer to the queue
if (!tryIoctl(VIDIOC_QBUF, &buffers[bufferIndex].buffer))