Implement MPLANE buffers
The qualcomm driver (on MSM8916 at least) uses an MPLANE buffer for the video capture with a single plane in it. This detects such drivers and requests MPLANE buffers from the driver and then always uses the first plane from that through the normal pipeline.
This commit is contained in:
154
main.c
154
main.c
@@ -57,6 +57,7 @@ struct camerainfo {
|
|||||||
int rotate;
|
int rotate;
|
||||||
int fmt;
|
int fmt;
|
||||||
int mbus;
|
int mbus;
|
||||||
|
enum v4l2_buf_type type;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
char media_dev_name[260];
|
char media_dev_name[260];
|
||||||
@@ -95,6 +96,7 @@ static float colormatrix_srgb[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct buffer *buffers;
|
struct buffer *buffers;
|
||||||
|
struct v4l2_plane buf_planes[1];
|
||||||
static unsigned int n_buffers;
|
static unsigned int n_buffers;
|
||||||
|
|
||||||
struct camerainfo current;
|
struct camerainfo current;
|
||||||
@@ -175,22 +177,24 @@ remap(int value, int input_min, int input_max, int output_min, int output_max)
|
|||||||
static void
|
static void
|
||||||
start_capturing(int fd)
|
start_capturing(int fd)
|
||||||
{
|
{
|
||||||
enum v4l2_buf_type type;
|
|
||||||
|
|
||||||
for (int i = 0; i < n_buffers; ++i) {
|
for (int i = 0; i < n_buffers; ++i) {
|
||||||
struct v4l2_buffer buf = {
|
struct v4l2_buffer buf = {
|
||||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
.type = current.type,
|
||||||
.memory = V4L2_MEMORY_MMAP,
|
.memory = V4L2_MEMORY_MMAP,
|
||||||
.index = i,
|
.index = i,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||||
|
buf.m.planes = buf_planes;
|
||||||
|
buf.length = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_QBUF, &buf) == -1) {
|
if (xioctl(fd, VIDIOC_QBUF, &buf) == -1) {
|
||||||
errno_exit("VIDIOC_QBUF");
|
errno_exit("VIDIOC_QBUF");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
if (xioctl(fd, VIDIOC_STREAMON, ¤t.type) == -1) {
|
||||||
if (xioctl(fd, VIDIOC_STREAMON, &type) == -1) {
|
|
||||||
errno_exit("VIDIOC_STREAMON");
|
errno_exit("VIDIOC_STREAMON");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,8 +208,7 @@ stop_capturing(int fd)
|
|||||||
ready = 0;
|
ready = 0;
|
||||||
printf("Stopping capture\n");
|
printf("Stopping capture\n");
|
||||||
|
|
||||||
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
if (xioctl(fd, VIDIOC_STREAMOFF, ¤t.type) == -1) {
|
||||||
if (xioctl(fd, VIDIOC_STREAMOFF, &type) == -1) {
|
|
||||||
errno_exit("VIDIOC_STREAMOFF");
|
errno_exit("VIDIOC_STREAMOFF");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,10 +221,11 @@ stop_capturing(int fd)
|
|||||||
static void
|
static void
|
||||||
init_mmap(int fd)
|
init_mmap(int fd)
|
||||||
{
|
{
|
||||||
struct v4l2_requestbuffers req = {0};
|
struct v4l2_requestbuffers req = {
|
||||||
req.count = 4;
|
.count = 4,
|
||||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
.type = current.type,
|
||||||
req.memory = V4L2_MEMORY_MMAP;
|
.memory = V4L2_MEMORY_MMAP,
|
||||||
|
};
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
|
if (xioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||||
if (errno == EINVAL) {
|
if (errno == EINVAL) {
|
||||||
@@ -248,21 +252,35 @@ init_mmap(int fd)
|
|||||||
|
|
||||||
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
|
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
|
||||||
struct v4l2_buffer buf = {
|
struct v4l2_buffer buf = {
|
||||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
.type = current.type,
|
||||||
.memory = V4L2_MEMORY_MMAP,
|
.memory = V4L2_MEMORY_MMAP,
|
||||||
.index = n_buffers,
|
.index = n_buffers,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||||
|
buf.m.planes = buf_planes;
|
||||||
|
buf.length = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
|
if (xioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
|
||||||
errno_exit("VIDIOC_QUERYBUF");
|
errno_exit("VIDIOC_QUERYBUF");
|
||||||
}
|
}
|
||||||
|
|
||||||
buffers[n_buffers].length = buf.length;
|
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||||
buffers[n_buffers].start = mmap(NULL /* start anywhere */,
|
buffers[n_buffers].length = buf.m.planes[0].length;
|
||||||
buf.length,
|
buffers[n_buffers].start = mmap(NULL /* start anywhere */,
|
||||||
PROT_READ | PROT_WRITE /* required */,
|
buf.m.planes[0].length,
|
||||||
MAP_SHARED /* recommended */,
|
PROT_READ | PROT_WRITE /* required */,
|
||||||
fd, buf.m.offset);
|
MAP_SHARED /* recommended */,
|
||||||
|
fd, buf.m.planes[0].m.mem_offset);
|
||||||
|
} else {
|
||||||
|
buffers[n_buffers].length = buf.length;
|
||||||
|
buffers[n_buffers].start = mmap(NULL /* start anywhere */,
|
||||||
|
buf.length,
|
||||||
|
PROT_READ | PROT_WRITE /* required */,
|
||||||
|
MAP_SHARED /* recommended */,
|
||||||
|
fd, buf.m.offset);
|
||||||
|
}
|
||||||
|
|
||||||
if (MAP_FAILED == buffers[n_buffers].start) {
|
if (MAP_FAILED == buffers[n_buffers].start) {
|
||||||
errno_exit("mmap");
|
errno_exit("mmap");
|
||||||
@@ -497,7 +515,13 @@ init_device(int fd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
// Detect buffer format for the interface node, preferring normal video capture
|
||||||
|
if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
|
||||||
|
current.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
} else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) {
|
||||||
|
printf("[%s] Using the MPLANE buffer format\n", current.cfg_name);
|
||||||
|
current.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||||
|
} else {
|
||||||
fprintf(stderr, "%s is no video capture device\n",
|
fprintf(stderr, "%s is no video capture device\n",
|
||||||
current.dev_name);
|
current.dev_name);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@@ -511,12 +535,12 @@ init_device(int fd)
|
|||||||
|
|
||||||
/* Select video input, video standard and tune here. */
|
/* Select video input, video standard and tune here. */
|
||||||
struct v4l2_cropcap cropcap = {
|
struct v4l2_cropcap cropcap = {
|
||||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
.type = current.type,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct v4l2_crop crop = {0};
|
struct v4l2_crop crop = {0};
|
||||||
if (xioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0) {
|
if (xioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0) {
|
||||||
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
crop.type = current.type;
|
||||||
crop.c = cropcap.defrect; /* reset to default */
|
crop.c = cropcap.defrect; /* reset to default */
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1) {
|
if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1) {
|
||||||
@@ -533,26 +557,43 @@ init_device(int fd)
|
|||||||
/* Errors ignored. */
|
/* Errors ignored. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Request a video format
|
||||||
struct v4l2_format fmt = {
|
struct v4l2_format fmt = {
|
||||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
.type = current.type,
|
||||||
};
|
};
|
||||||
if (current.width > 0) {
|
if (current.width > 0) {
|
||||||
g_print("Setting camera to %dx%d fmt %d\n",
|
g_print("Setting camera to %dx%d fmt %d\n",
|
||||||
current.width, current.height, current.fmt);
|
current.width, current.height, current.fmt);
|
||||||
fmt.fmt.pix.width = current.width;
|
|
||||||
fmt.fmt.pix.height = current.height;
|
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||||
fmt.fmt.pix.pixelformat = current.fmt;
|
fmt.fmt.pix_mp.width = current.width;
|
||||||
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
fmt.fmt.pix_mp.height = current.height;
|
||||||
|
fmt.fmt.pix_mp.pixelformat = current.fmt;
|
||||||
|
fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
|
||||||
|
} else {
|
||||||
|
fmt.fmt.pix.width = current.width;
|
||||||
|
fmt.fmt.pix.height = current.height;
|
||||||
|
fmt.fmt.pix.pixelformat = current.fmt;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
||||||
|
}
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
|
if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
|
||||||
g_printerr("VIDIOC_S_FMT failed");
|
g_printerr("VIDIOC_S_FMT failed");
|
||||||
show_error("Could not set camera mode");
|
show_error("Could not set camera mode");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fmt.fmt.pix.width != current.width ||
|
|
||||||
|
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
|
||||||
|
&& (fmt.fmt.pix_mp.width != current.width ||
|
||||||
|
fmt.fmt.pix_mp.height != current.height ||
|
||||||
|
fmt.fmt.pix_mp.pixelformat != current.fmt))
|
||||||
|
g_printerr("Driver returned %dx%d fmt %d\n",
|
||||||
|
fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
|
||||||
|
fmt.fmt.pix_mp.pixelformat);
|
||||||
|
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
|
||||||
|
&& (fmt.fmt.pix.width != current.width ||
|
||||||
fmt.fmt.pix.height != current.height ||
|
fmt.fmt.pix.height != current.height ||
|
||||||
fmt.fmt.pix.pixelformat != current.fmt)
|
fmt.fmt.pix.pixelformat != current.fmt))
|
||||||
g_printerr("Driver returned %dx%d fmt %d\n",
|
g_printerr("Driver returned %dx%d fmt %d\n",
|
||||||
fmt.fmt.pix.width, fmt.fmt.pix.height,
|
fmt.fmt.pix.width, fmt.fmt.pix.height,
|
||||||
fmt.fmt.pix.pixelformat);
|
fmt.fmt.pix.pixelformat);
|
||||||
@@ -563,22 +604,24 @@ init_device(int fd)
|
|||||||
if (xioctl(fd, VIDIOC_G_FMT, &fmt) == -1) {
|
if (xioctl(fd, VIDIOC_G_FMT, &fmt) == -1) {
|
||||||
errno_exit("VIDIOC_G_FMT");
|
errno_exit("VIDIOC_G_FMT");
|
||||||
}
|
}
|
||||||
g_print("Got %dx%d fmt %d from the driver\n",
|
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||||
fmt.fmt.pix.width, fmt.fmt.pix.height,
|
g_print("Got %dx%d fmt %d from the driver\n",
|
||||||
fmt.fmt.pix.pixelformat);
|
fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
|
||||||
current.width = fmt.fmt.pix.width;
|
fmt.fmt.pix_mp.pixelformat);
|
||||||
current.height = fmt.fmt.pix.height;
|
current.width = fmt.fmt.pix.width;
|
||||||
|
current.height = fmt.fmt.pix.height;
|
||||||
|
} else {
|
||||||
|
g_print("Got %dx%d fmt %d from the driver\n",
|
||||||
|
fmt.fmt.pix.width, fmt.fmt.pix.height,
|
||||||
|
fmt.fmt.pix.pixelformat);
|
||||||
|
current.width = fmt.fmt.pix_mp.width;
|
||||||
|
current.height = fmt.fmt.pix_mp.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
current.fmt = fmt.fmt.pix.pixelformat;
|
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||||
|
current.fmt = fmt.fmt.pix_mp.pixelformat;
|
||||||
/* Buggy driver paranoia. */
|
} else {
|
||||||
unsigned int min = fmt.fmt.pix.width * 2;
|
current.fmt = fmt.fmt.pix.pixelformat;
|
||||||
if (fmt.fmt.pix.bytesperline < min) {
|
|
||||||
fmt.fmt.pix.bytesperline = min;
|
|
||||||
}
|
|
||||||
min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
|
|
||||||
if (fmt.fmt.pix.sizeimage < min) {
|
|
||||||
fmt.fmt.pix.sizeimage = min;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init_mmap(fd);
|
init_mmap(fd);
|
||||||
@@ -897,10 +940,19 @@ preview_configure(GtkWidget *widget, GdkEventConfigure *event)
|
|||||||
static int
|
static int
|
||||||
read_frame(int fd)
|
read_frame(int fd)
|
||||||
{
|
{
|
||||||
struct v4l2_buffer buf = {0};
|
int bytesused;
|
||||||
|
|
||||||
|
struct v4l2_buffer buf = {
|
||||||
|
.type = current.type,
|
||||||
|
.memory = V4L2_MEMORY_MMAP,
|
||||||
|
.index = n_buffers,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||||
|
buf.m.planes = buf_planes;
|
||||||
|
buf.length = 1;
|
||||||
|
}
|
||||||
|
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
if (xioctl(fd, VIDIOC_DQBUF, &buf) == -1) {
|
if (xioctl(fd, VIDIOC_DQBUF, &buf) == -1) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
@@ -914,9 +966,13 @@ read_frame(int fd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//assert(buf.index < n_buffers);
|
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||||
|
bytesused = buf.m.planes[0].bytesused;
|
||||||
|
} else {
|
||||||
|
bytesused = buf.bytesused;
|
||||||
|
}
|
||||||
|
|
||||||
process_image(buffers[buf.index].start, buf.bytesused);
|
process_image(buffers[buf.index].start, bytesused);
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_QBUF, &buf) == -1) {
|
if (xioctl(fd, VIDIOC_QBUF, &buf) == -1) {
|
||||||
errno_exit("VIDIOC_QBUF");
|
errno_exit("VIDIOC_QBUF");
|
||||||
|
Reference in New Issue
Block a user