mirror of
https://github.com/opencv/opencv.git
synced 2025-06-26 22:31:22 +08:00
V4L2: Add multi-planar capture support
Devices which only support multi-planar capture cannot be processed as single-planar. Add multi-planar support to v4l driver.
This commit is contained in:
parent
925ff6241f
commit
a001ab3a44
@ -286,6 +286,12 @@ typedef uint32_t __u32;
|
||||
#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
|
||||
|
||||
@ -317,17 +323,27 @@ static const char* decode_ioctl_code(unsigned long ioctlCode)
|
||||
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();
|
||||
}
|
||||
@ -374,6 +390,7 @@ struct CvCaptureCAM_V4L CV_FINAL : public CvCapture
|
||||
v4l2_format form;
|
||||
v4l2_requestbuffers req;
|
||||
v4l2_buf_type type;
|
||||
unsigned char num_planes;
|
||||
|
||||
timeval timestamp;
|
||||
|
||||
@ -430,6 +447,7 @@ CvCaptureCAM_V4L::CvCaptureCAM_V4L() :
|
||||
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();
|
||||
@ -472,15 +490,24 @@ bool CvCaptureCAM_V4L::isOpened() const
|
||||
bool CvCaptureCAM_V4L::try_palette_v4l2()
|
||||
{
|
||||
form = v4l2_format();
|
||||
form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -534,12 +561,15 @@ bool CvCaptureCAM_V4L::try_init_v4l2()
|
||||
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;
|
||||
}
|
||||
|
||||
@ -603,7 +633,7 @@ bool CvCaptureCAM_V4L::setFps(int value)
|
||||
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))
|
||||
@ -652,12 +682,21 @@ bool CvCaptureCAM_V4L::convertableToRgb() const
|
||||
|
||||
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:
|
||||
@ -689,9 +728,19 @@ void CvCaptureCAM_V4L::v4l2_create_frame()
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -723,7 +772,7 @@ bool CvCaptureCAM_V4L::initCapture()
|
||||
|
||||
/* Find Window info */
|
||||
form = v4l2_format();
|
||||
form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
form.type = type;
|
||||
|
||||
if (!tryIoctl(VIDIOC_G_FMT, &form))
|
||||
{
|
||||
@ -743,9 +792,12 @@ bool CvCaptureCAM_V4L::initCapture()
|
||||
/* try to set framerate */
|
||||
setFps(fps);
|
||||
|
||||
/* Buggy driver paranoia. */
|
||||
if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
|
||||
// TODO: add size adjustment if needed
|
||||
} else {
|
||||
unsigned int min;
|
||||
|
||||
/* Buggy driver paranoia. */
|
||||
min = form.fmt.pix.width * 2;
|
||||
|
||||
if (form.fmt.pix.bytesperline < min)
|
||||
@ -755,6 +807,12 @@ bool CvCaptureCAM_V4L::initCapture()
|
||||
|
||||
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;
|
||||
@ -800,7 +858,7 @@ bool CvCaptureCAM_V4L::requestBuffers(unsigned int buffer_number)
|
||||
|
||||
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)) {
|
||||
@ -824,34 +882,56 @@ bool CvCaptureCAM_V4L::createBuffers()
|
||||
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 =
|
||||
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;
|
||||
}
|
||||
|
||||
buffers[n_buffers].memories[n_planes].length = length;
|
||||
buffers[n_buffers].memories[n_planes].start =
|
||||
mmap(NULL /* start anywhere */,
|
||||
buf.length,
|
||||
length,
|
||||
PROT_READ /* required */,
|
||||
MAP_SHARED /* recommended */,
|
||||
deviceHandle, 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) << ")");
|
||||
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;
|
||||
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].start != 0;
|
||||
return (buffers[MAX_V4L_BUFFERS].memories[MEMORY_ORIG].start != 0) &&
|
||||
(buffers[MAX_V4L_BUFFERS].memories[MEMORY_RGB].start != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -933,8 +1013,13 @@ bool CvCaptureCAM_V4L::open(const char* _deviceName)
|
||||
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;
|
||||
@ -951,12 +1036,33 @@ bool CvCaptureCAM_V4L::read_frame_v4l2()
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1042,10 +1148,15 @@ bool CvCaptureCAM_V4L::grabFrame()
|
||||
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) << ")");
|
||||
@ -1534,35 +1645,51 @@ static int sonix_decompress(int width, int height, unsigned char *inp, unsigned
|
||||
|
||||
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;
|
||||
@ -1571,69 +1698,69 @@ void CvCaptureCAM_V4L::convertToRgb(const Buffer ¤tBuffer)
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1904,8 +2031,14 @@ double CvCaptureCAM_V4L::getProperty(int property_id) const
|
||||
{
|
||||
switch (property_id) {
|
||||
case cv::CAP_PROP_FRAME_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:
|
||||
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;
|
||||
@ -1922,7 +2055,7 @@ double CvCaptureCAM_V4L::getProperty(int property_id) const
|
||||
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;
|
||||
@ -2063,9 +2196,14 @@ void CvCaptureCAM_V4L::releaseBuffers()
|
||||
{
|
||||
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;
|
||||
@ -2076,11 +2214,14 @@ void CvCaptureCAM_V4L::releaseBuffers()
|
||||
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)) {
|
||||
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].start = 0;
|
||||
buffers[n_buffers].memories[n_planes].start = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2100,7 +2241,6 @@ bool CvCaptureCAM_V4L::streaming(bool startStream)
|
||||
return !startStream;
|
||||
}
|
||||
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
bool result = tryIoctl(startStream ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &type);
|
||||
if (result)
|
||||
{
|
||||
@ -2133,13 +2273,26 @@ IplImage *CvCaptureCAM_V4L::retrieveFrame(int)
|
||||
} 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))
|
||||
|
Loading…
Reference in New Issue
Block a user