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:
parent
69a98fe9d4
commit
f108fe7d06
154
main.c
154
main.c
|
@ -57,6 +57,7 @@ struct camerainfo {
|
|||
int rotate;
|
||||
int fmt;
|
||||
int mbus;
|
||||
enum v4l2_buf_type type;
|
||||
int fd;
|
||||
|
||||
char media_dev_name[260];
|
||||
|
@ -95,6 +96,7 @@ static float colormatrix_srgb[] = {
|
|||
};
|
||||
|
||||
struct buffer *buffers;
|
||||
struct v4l2_plane buf_planes[1];
|
||||
static unsigned int n_buffers;
|
||||
|
||||
struct camerainfo current;
|
||||
|
@ -175,22 +177,24 @@ remap(int value, int input_min, int input_max, int output_min, int output_max)
|
|||
static void
|
||||
start_capturing(int fd)
|
||||
{
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
for (int i = 0; i < n_buffers; ++i) {
|
||||
struct v4l2_buffer buf = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
||||
.type = current.type,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
.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) {
|
||||
errno_exit("VIDIOC_QBUF");
|
||||
}
|
||||
}
|
||||
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (xioctl(fd, VIDIOC_STREAMON, &type) == -1) {
|
||||
if (xioctl(fd, VIDIOC_STREAMON, ¤t.type) == -1) {
|
||||
errno_exit("VIDIOC_STREAMON");
|
||||
}
|
||||
|
||||
|
@ -204,8 +208,7 @@ stop_capturing(int fd)
|
|||
ready = 0;
|
||||
printf("Stopping capture\n");
|
||||
|
||||
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (xioctl(fd, VIDIOC_STREAMOFF, &type) == -1) {
|
||||
if (xioctl(fd, VIDIOC_STREAMOFF, ¤t.type) == -1) {
|
||||
errno_exit("VIDIOC_STREAMOFF");
|
||||
}
|
||||
|
||||
|
@ -218,10 +221,11 @@ stop_capturing(int fd)
|
|||
static void
|
||||
init_mmap(int fd)
|
||||
{
|
||||
struct v4l2_requestbuffers req = {0};
|
||||
req.count = 4;
|
||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
struct v4l2_requestbuffers req = {
|
||||
.count = 4,
|
||||
.type = current.type,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
};
|
||||
|
||||
if (xioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||
if (errno == EINVAL) {
|
||||
|
@ -248,21 +252,35 @@ init_mmap(int fd)
|
|||
|
||||
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
|
||||
struct v4l2_buffer buf = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
||||
.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;
|
||||
}
|
||||
|
||||
if (xioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
|
||||
errno_exit("VIDIOC_QUERYBUF");
|
||||
}
|
||||
|
||||
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 (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||
buffers[n_buffers].length = buf.m.planes[0].length;
|
||||
buffers[n_buffers].start = mmap(NULL /* start anywhere */,
|
||||
buf.m.planes[0].length,
|
||||
PROT_READ | PROT_WRITE /* required */,
|
||||
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) {
|
||||
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",
|
||||
current.dev_name);
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -511,12 +535,12 @@ init_device(int fd)
|
|||
|
||||
/* Select video input, video standard and tune here. */
|
||||
struct v4l2_cropcap cropcap = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
||||
.type = current.type,
|
||||
};
|
||||
|
||||
struct v4l2_crop crop = {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 */
|
||||
|
||||
if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1) {
|
||||
|
@ -533,26 +557,43 @@ init_device(int fd)
|
|||
/* Errors ignored. */
|
||||
}
|
||||
|
||||
|
||||
// Request a video format
|
||||
struct v4l2_format fmt = {
|
||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
||||
.type = current.type,
|
||||
};
|
||||
if (current.width > 0) {
|
||||
g_print("Setting camera to %dx%d fmt %d\n",
|
||||
current.width, current.height, current.fmt);
|
||||
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 (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;
|
||||
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) {
|
||||
g_printerr("VIDIOC_S_FMT failed");
|
||||
show_error("Could not set camera mode");
|
||||
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.pixelformat != current.fmt)
|
||||
fmt.fmt.pix.pixelformat != current.fmt))
|
||||
g_printerr("Driver returned %dx%d fmt %d\n",
|
||||
fmt.fmt.pix.width, fmt.fmt.pix.height,
|
||||
fmt.fmt.pix.pixelformat);
|
||||
|
@ -563,22 +604,24 @@ init_device(int fd)
|
|||
if (xioctl(fd, VIDIOC_G_FMT, &fmt) == -1) {
|
||||
errno_exit("VIDIOC_G_FMT");
|
||||
}
|
||||
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.width;
|
||||
current.height = fmt.fmt.pix.height;
|
||||
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||
g_print("Got %dx%d fmt %d from the driver\n",
|
||||
fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
|
||||
fmt.fmt.pix_mp.pixelformat);
|
||||
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;
|
||||
|
||||
/* Buggy driver paranoia. */
|
||||
unsigned int min = fmt.fmt.pix.width * 2;
|
||||
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;
|
||||
if (current.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||
current.fmt = fmt.fmt.pix_mp.pixelformat;
|
||||
} else {
|
||||
current.fmt = fmt.fmt.pix.pixelformat;
|
||||
}
|
||||
|
||||
init_mmap(fd);
|
||||
|
@ -897,10 +940,19 @@ preview_configure(GtkWidget *widget, GdkEventConfigure *event)
|
|||
static int
|
||||
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) {
|
||||
switch (errno) {
|
||||
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) {
|
||||
errno_exit("VIDIOC_QBUF");
|
||||
|
|
Loading…
Reference in New Issue