Add libmegapixels
This commit is contained in:
514
src/camera.c
514
src/camera.c
@@ -1,9 +1,9 @@
|
||||
#include "camera.h"
|
||||
#include "mode.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <libmegapixels.h>
|
||||
#include <linux/v4l2-subdev.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
@@ -11,9 +11,6 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_VIDEO_BUFFERS 20
|
||||
#define MAX_BG_TASKS 8
|
||||
|
||||
static void
|
||||
errno_printerr(const char *s)
|
||||
{
|
||||
@@ -37,12 +34,7 @@ struct video_buffer {
|
||||
};
|
||||
|
||||
struct _MPCamera {
|
||||
int video_fd;
|
||||
int subdev_fd;
|
||||
int bridge_fd;
|
||||
|
||||
bool has_set_mode;
|
||||
MPMode current_mode;
|
||||
libmegapixels_camera *camera;
|
||||
|
||||
struct video_buffer buffers[MAX_VIDEO_BUFFERS];
|
||||
uint32_t num_buffers;
|
||||
@@ -54,13 +46,12 @@ struct _MPCamera {
|
||||
};
|
||||
|
||||
MPCamera *
|
||||
mp_camera_new(int video_fd, int subdev_fd, int bridge_fd)
|
||||
mp_camera_new(libmegapixels_camera *camera)
|
||||
{
|
||||
g_return_val_if_fail(video_fd != -1, NULL);
|
||||
|
||||
libmegapixels_open(camera);
|
||||
// Query capabilities
|
||||
struct v4l2_capability cap;
|
||||
if (xioctl(video_fd, VIDIOC_QUERYCAP, &cap) == -1) {
|
||||
if (xioctl(camera->video_fd, VIDIOC_QUERYCAP, &cap) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -73,31 +64,14 @@ mp_camera_new(int video_fd, int subdev_fd, int bridge_fd)
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
libmegapixels_close(camera);
|
||||
|
||||
MPCamera *camera = malloc(sizeof(MPCamera));
|
||||
camera->video_fd = video_fd;
|
||||
camera->subdev_fd = subdev_fd;
|
||||
camera->bridge_fd = bridge_fd;
|
||||
camera->has_set_mode = false;
|
||||
camera->num_buffers = 0;
|
||||
camera->use_mplane = use_mplane;
|
||||
memset(camera->child_bg_pids,
|
||||
0,
|
||||
sizeof(camera->child_bg_pids[0]) * MAX_BG_TASKS);
|
||||
return camera;
|
||||
}
|
||||
|
||||
void
|
||||
mp_camera_free(MPCamera *camera)
|
||||
{
|
||||
mp_camera_wait_bg_tasks(camera);
|
||||
|
||||
g_warn_if_fail(camera->num_buffers == 0);
|
||||
if (camera->num_buffers != 0) {
|
||||
mp_camera_stop_capture(camera);
|
||||
}
|
||||
|
||||
free(camera);
|
||||
MPCamera *cam = malloc(sizeof(MPCamera));
|
||||
cam->camera = camera;
|
||||
cam->num_buffers = 0;
|
||||
cam->use_mplane = use_mplane;
|
||||
memset(cam->child_bg_pids, 0, sizeof(cam->child_bg_pids[0]) * MAX_BG_TASKS);
|
||||
return cam;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -180,22 +154,10 @@ mp_camera_check_task_complete(MPCamera *camera, pid_t pid)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_is_subdev(MPCamera *camera)
|
||||
{
|
||||
return camera->subdev_fd != -1;
|
||||
}
|
||||
|
||||
int
|
||||
mp_camera_get_video_fd(MPCamera *camera)
|
||||
{
|
||||
return camera->video_fd;
|
||||
}
|
||||
|
||||
int
|
||||
mp_camera_get_subdev_fd(MPCamera *camera)
|
||||
{
|
||||
return camera->subdev_fd;
|
||||
return camera->camera->video_fd;
|
||||
}
|
||||
|
||||
static enum v4l2_buf_type
|
||||
@@ -207,151 +169,9 @@ get_buf_type(MPCamera *camera)
|
||||
return V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
}
|
||||
|
||||
static bool
|
||||
camera_mode_impl(MPCamera *camera, int request, MPMode *mode)
|
||||
{
|
||||
uint32_t pixfmt = mp_pixel_format_to_v4l_pixel_format(mode->pixel_format);
|
||||
struct v4l2_format fmt = {};
|
||||
if (camera->use_mplane) {
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
fmt.fmt.pix_mp.width = mode->width;
|
||||
fmt.fmt.pix_mp.height = mode->height;
|
||||
fmt.fmt.pix_mp.pixelformat = pixfmt;
|
||||
fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
|
||||
} else {
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
fmt.fmt.pix.width = mode->width;
|
||||
fmt.fmt.pix.height = mode->height;
|
||||
fmt.fmt.pix.pixelformat = pixfmt;
|
||||
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
||||
}
|
||||
|
||||
if (xioctl(camera->video_fd, request, &fmt) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (camera->use_mplane) {
|
||||
mode->width = fmt.fmt.pix_mp.width;
|
||||
mode->height = fmt.fmt.pix_mp.height;
|
||||
mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(
|
||||
fmt.fmt.pix_mp.pixelformat);
|
||||
} else {
|
||||
mode->width = fmt.fmt.pix.width;
|
||||
mode->height = fmt.fmt.pix.height;
|
||||
mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(
|
||||
fmt.fmt.pix.pixelformat);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_try_mode(MPCamera *camera, MPMode *mode)
|
||||
{
|
||||
if (!camera_mode_impl(camera, VIDIOC_TRY_FMT, mode)) {
|
||||
errno_printerr("VIDIOC_S_FMT");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const MPMode *
|
||||
mp_camera_get_mode(const MPCamera *camera)
|
||||
{
|
||||
return &camera->current_mode;
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_set_mode(MPCamera *camera, MPMode *mode)
|
||||
{
|
||||
// Set the mode in the subdev the camera is one
|
||||
if (mp_camera_is_subdev(camera)) {
|
||||
struct v4l2_subdev_frame_interval interval = {};
|
||||
interval.pad = 0;
|
||||
interval.interval = mode->frame_interval;
|
||||
if (xioctl(camera->subdev_fd,
|
||||
VIDIOC_SUBDEV_S_FRAME_INTERVAL,
|
||||
&interval) == -1) {
|
||||
errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
|
||||
}
|
||||
|
||||
bool did_set_frame_rate = interval.interval.numerator ==
|
||||
mode->frame_interval.numerator &&
|
||||
interval.interval.denominator ==
|
||||
mode->frame_interval.denominator;
|
||||
|
||||
struct v4l2_subdev_format fmt = {};
|
||||
fmt.pad = 0;
|
||||
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
fmt.format.width = mode->width;
|
||||
fmt.format.height = mode->height;
|
||||
fmt.format.code =
|
||||
mp_pixel_format_to_v4l_bus_code(mode->pixel_format);
|
||||
fmt.format.field = V4L2_FIELD_ANY;
|
||||
if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FMT, &fmt) == -1) {
|
||||
errno_printerr("VIDIOC_SUBDEV_S_FMT");
|
||||
return false;
|
||||
}
|
||||
|
||||
// sun6i-csi-bridge will return EINVAL when trying to read
|
||||
// frames if the resolution it's configured with doesn't match
|
||||
// the resolution of its input.
|
||||
if (camera->bridge_fd > 0) {
|
||||
struct v4l2_subdev_format bridge_fmt = fmt;
|
||||
|
||||
if (xioctl(camera->bridge_fd,
|
||||
VIDIOC_SUBDEV_S_FMT,
|
||||
&bridge_fmt) == -1) {
|
||||
errno_printerr("VIDIOC_SUBDEV_S_FMT");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fmt.format.width != bridge_fmt.format.width ||
|
||||
fmt.format.height != bridge_fmt.format.height) {
|
||||
g_printerr("Bridge format resolution mismatch\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Some drivers like ov5640 don't allow you to set the frame format
|
||||
// with too high a frame-rate, but that means the frame-rate won't be
|
||||
// set after the format change. So we need to try again here if we
|
||||
// didn't succeed before. Ideally we'd be able to set both at once.
|
||||
if (!did_set_frame_rate) {
|
||||
interval.interval = mode->frame_interval;
|
||||
if (xioctl(camera->subdev_fd,
|
||||
VIDIOC_SUBDEV_S_FRAME_INTERVAL,
|
||||
&interval) == -1) {
|
||||
errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
|
||||
}
|
||||
}
|
||||
|
||||
// Update the mode
|
||||
mode->pixel_format =
|
||||
mp_pixel_format_from_v4l_bus_code(fmt.format.code);
|
||||
mode->frame_interval = interval.interval;
|
||||
mode->width = fmt.format.width;
|
||||
mode->height = fmt.format.height;
|
||||
}
|
||||
|
||||
// Set the mode for the video device
|
||||
{
|
||||
if (!camera_mode_impl(camera, VIDIOC_S_FMT, mode)) {
|
||||
errno_printerr("VIDIOC_S_FMT");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
camera->has_set_mode = true;
|
||||
camera->current_mode = *mode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_start_capture(MPCamera *camera)
|
||||
{
|
||||
g_return_val_if_fail(camera->has_set_mode, false);
|
||||
g_return_val_if_fail(camera->num_buffers == 0, false);
|
||||
|
||||
const enum v4l2_buf_type buftype = get_buf_type(camera);
|
||||
@@ -362,7 +182,7 @@ mp_camera_start_capture(MPCamera *camera)
|
||||
req.type = buftype;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||
errno_printerr("VIDIOC_REQBUFS");
|
||||
return false;
|
||||
}
|
||||
@@ -388,7 +208,7 @@ mp_camera_start_capture(MPCamera *camera)
|
||||
buf.length = 1;
|
||||
}
|
||||
|
||||
if (xioctl(camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) {
|
||||
errno_printerr("VIDIOC_QUERYBUF");
|
||||
break;
|
||||
}
|
||||
@@ -399,7 +219,7 @@ mp_camera_start_capture(MPCamera *camera)
|
||||
planes[0].length,
|
||||
PROT_READ,
|
||||
MAP_SHARED,
|
||||
camera->video_fd,
|
||||
camera->camera->video_fd,
|
||||
planes[0].m.mem_offset);
|
||||
} else {
|
||||
camera->buffers[i].length = buf.length;
|
||||
@@ -407,7 +227,7 @@ mp_camera_start_capture(MPCamera *camera)
|
||||
buf.length,
|
||||
PROT_READ,
|
||||
MAP_SHARED,
|
||||
camera->video_fd,
|
||||
camera->camera->video_fd,
|
||||
buf.m.offset);
|
||||
}
|
||||
|
||||
@@ -420,7 +240,7 @@ mp_camera_start_capture(MPCamera *camera)
|
||||
.type = buftype,
|
||||
.index = i,
|
||||
};
|
||||
if (xioctl(camera->video_fd, VIDIOC_EXPBUF, &expbuf) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_EXPBUF, &expbuf) == -1) {
|
||||
errno_printerr("VIDIOC_EXPBUF");
|
||||
break;
|
||||
}
|
||||
@@ -449,7 +269,7 @@ mp_camera_start_capture(MPCamera *camera)
|
||||
}
|
||||
|
||||
// Queue the buffer for capture
|
||||
if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
|
||||
errno_printerr("VIDIOC_QBUF");
|
||||
goto error;
|
||||
}
|
||||
@@ -457,7 +277,7 @@ mp_camera_start_capture(MPCamera *camera)
|
||||
|
||||
// Start capture
|
||||
enum v4l2_buf_type type = buftype;
|
||||
if (xioctl(camera->video_fd, VIDIOC_STREAMON, &type) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_STREAMON, &type) == -1) {
|
||||
errno_printerr("VIDIOC_STREAMON");
|
||||
goto error;
|
||||
}
|
||||
@@ -485,7 +305,7 @@ error:
|
||||
req.type = buftype;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||
errno_printerr("VIDIOC_REQBUFS");
|
||||
}
|
||||
}
|
||||
@@ -501,7 +321,7 @@ mp_camera_stop_capture(MPCamera *camera)
|
||||
const enum v4l2_buf_type buftype = get_buf_type(camera);
|
||||
|
||||
enum v4l2_buf_type type = buftype;
|
||||
if (xioctl(camera->video_fd, VIDIOC_STREAMOFF, &type) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_STREAMOFF, &type) == -1) {
|
||||
errno_printerr("VIDIOC_STREAMOFF");
|
||||
}
|
||||
|
||||
@@ -523,7 +343,7 @@ mp_camera_stop_capture(MPCamera *camera)
|
||||
req.count = 0;
|
||||
req.type = buftype;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||
errno_printerr("VIDIOC_REQBUFS");
|
||||
}
|
||||
|
||||
@@ -551,7 +371,7 @@ mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer)
|
||||
buf.length = 1;
|
||||
}
|
||||
|
||||
if (xioctl(camera->video_fd, VIDIOC_DQBUF, &buf) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_DQBUF, &buf) == -1) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
return true;
|
||||
@@ -565,9 +385,9 @@ mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pixel_format = camera->current_mode.pixel_format;
|
||||
uint32_t width = camera->current_mode.width;
|
||||
uint32_t height = camera->current_mode.height;
|
||||
int format = camera->camera->current_mode->format;
|
||||
uint32_t width = camera->camera->current_mode->width;
|
||||
uint32_t height = camera->camera->current_mode->height;
|
||||
|
||||
uint32_t bytesused;
|
||||
if (camera->use_mplane) {
|
||||
@@ -576,8 +396,8 @@ mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer)
|
||||
bytesused = buf.bytesused;
|
||||
}
|
||||
|
||||
assert(bytesused == (mp_pixel_format_width_to_bytes(pixel_format, width) +
|
||||
mp_pixel_format_width_to_padding(pixel_format, width)) *
|
||||
assert(bytesused == (libmegapixels_mode_width_to_bytes(format, width) +
|
||||
libmegapixels_mode_width_to_padding(format, width)) *
|
||||
height);
|
||||
assert(bytesused == camera->buffers[buf.index].length);
|
||||
|
||||
@@ -604,243 +424,13 @@ mp_camera_release_buffer(MPCamera *camera, uint32_t buffer_index)
|
||||
buf.length = 1;
|
||||
}
|
||||
|
||||
if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
|
||||
if (xioctl(camera->camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
|
||||
errno_printerr("VIDIOC_QBUF");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static MPModeList *
|
||||
get_subdev_modes(MPCamera *camera, bool (*check)(MPCamera *, MPMode *))
|
||||
{
|
||||
MPModeList *item = NULL;
|
||||
|
||||
for (uint32_t fmt_index = 0;; ++fmt_index) {
|
||||
struct v4l2_subdev_mbus_code_enum fmt = {};
|
||||
fmt.index = fmt_index;
|
||||
fmt.pad = 0;
|
||||
fmt.which = V4L2_SUBDEV_FORMAT_TRY;
|
||||
if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &fmt) ==
|
||||
-1) {
|
||||
if (errno != EINVAL) {
|
||||
errno_printerr("VIDIOC_SUBDEV_ENUM_MBUS_CODE");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip unsupported formats
|
||||
uint32_t format = mp_pixel_format_from_v4l_bus_code(fmt.code);
|
||||
if (format == MP_PIXEL_FMT_UNSUPPORTED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t frame_index = 0;; ++frame_index) {
|
||||
struct v4l2_subdev_frame_size_enum frame = {};
|
||||
frame.index = frame_index;
|
||||
frame.pad = 0;
|
||||
frame.code = fmt.code;
|
||||
frame.which = V4L2_SUBDEV_FORMAT_TRY;
|
||||
if (xioctl(camera->subdev_fd,
|
||||
VIDIOC_SUBDEV_ENUM_FRAME_SIZE,
|
||||
&frame) == -1) {
|
||||
if (errno != EINVAL) {
|
||||
errno_printerr(
|
||||
"VIDIOC_SUBDEV_ENUM_FRAME_SIZE");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Handle other types
|
||||
if (frame.min_width != frame.max_width ||
|
||||
frame.min_height != frame.max_height) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint32_t interval_index = 0;; ++interval_index) {
|
||||
struct v4l2_subdev_frame_interval_enum interval = {};
|
||||
interval.index = interval_index;
|
||||
interval.pad = 0;
|
||||
interval.code = fmt.code;
|
||||
interval.width = frame.max_width;
|
||||
interval.height = frame.max_height;
|
||||
interval.which = V4L2_SUBDEV_FORMAT_TRY;
|
||||
if (xioctl(camera->subdev_fd,
|
||||
VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL,
|
||||
&interval) == -1) {
|
||||
if (errno != EINVAL) {
|
||||
errno_printerr(
|
||||
"VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
MPMode mode = {
|
||||
.pixel_format = format,
|
||||
.frame_interval = interval.interval,
|
||||
.width = frame.max_width,
|
||||
.height = frame.max_height,
|
||||
};
|
||||
|
||||
if (!check(camera, &mode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MPModeList *new_item = malloc(sizeof(MPModeList));
|
||||
new_item->mode = mode;
|
||||
new_item->next = item;
|
||||
item = new_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static MPModeList *
|
||||
get_video_modes(MPCamera *camera, bool (*check)(MPCamera *, MPMode *))
|
||||
{
|
||||
const enum v4l2_buf_type buftype = get_buf_type(camera);
|
||||
|
||||
MPModeList *item = NULL;
|
||||
|
||||
for (uint32_t fmt_index = 0;; ++fmt_index) {
|
||||
struct v4l2_fmtdesc fmt = {};
|
||||
fmt.index = fmt_index;
|
||||
fmt.type = buftype;
|
||||
if (xioctl(camera->video_fd, VIDIOC_ENUM_FMT, &fmt) == -1) {
|
||||
if (errno != EINVAL) {
|
||||
errno_printerr("VIDIOC_ENUM_FMT");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip unsupported formats
|
||||
uint32_t format =
|
||||
mp_pixel_format_from_v4l_pixel_format(fmt.pixelformat);
|
||||
if (format == MP_PIXEL_FMT_UNSUPPORTED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t frame_index = 0;; ++frame_index) {
|
||||
struct v4l2_frmsizeenum frame = {};
|
||||
frame.index = frame_index;
|
||||
frame.pixel_format = fmt.pixelformat;
|
||||
if (xioctl(camera->video_fd,
|
||||
VIDIOC_ENUM_FRAMESIZES,
|
||||
&frame) == -1) {
|
||||
if (errno != EINVAL) {
|
||||
errno_printerr("VIDIOC_ENUM_FRAMESIZES");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Handle other types
|
||||
if (frame.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint32_t interval_index = 0;; ++interval_index) {
|
||||
struct v4l2_frmivalenum interval = {};
|
||||
interval.index = interval_index;
|
||||
interval.pixel_format = fmt.pixelformat;
|
||||
interval.width = frame.discrete.width;
|
||||
interval.height = frame.discrete.height;
|
||||
if (xioctl(camera->video_fd,
|
||||
VIDIOC_ENUM_FRAMEINTERVALS,
|
||||
&interval) == -1) {
|
||||
if (errno != EINVAL) {
|
||||
errno_printerr(
|
||||
"VIDIOC_ENUM_FRAMESIZES");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Handle other types
|
||||
if (interval.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
|
||||
break;
|
||||
}
|
||||
|
||||
MPMode mode = {
|
||||
.pixel_format = format,
|
||||
.frame_interval = interval.discrete,
|
||||
.width = frame.discrete.width,
|
||||
.height = frame.discrete.height,
|
||||
};
|
||||
|
||||
if (!check(camera, &mode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MPModeList *new_item = malloc(sizeof(MPModeList));
|
||||
new_item->mode = mode;
|
||||
new_item->next = item;
|
||||
item = new_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static bool
|
||||
all_modes(MPCamera *camera, MPMode *mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
available_modes(MPCamera *camera, MPMode *mode)
|
||||
{
|
||||
MPMode attempt = *mode;
|
||||
return mp_camera_try_mode(camera, &attempt) &&
|
||||
mp_mode_is_equivalent(mode, &attempt);
|
||||
}
|
||||
|
||||
MPModeList *
|
||||
mp_camera_list_supported_modes(MPCamera *camera)
|
||||
{
|
||||
if (mp_camera_is_subdev(camera)) {
|
||||
return get_subdev_modes(camera, all_modes);
|
||||
} else {
|
||||
return get_video_modes(camera, all_modes);
|
||||
}
|
||||
}
|
||||
|
||||
MPModeList *
|
||||
mp_camera_list_available_modes(MPCamera *camera)
|
||||
{
|
||||
if (mp_camera_is_subdev(camera)) {
|
||||
return get_subdev_modes(camera, available_modes);
|
||||
} else {
|
||||
return get_video_modes(camera, available_modes);
|
||||
}
|
||||
}
|
||||
|
||||
MPMode *
|
||||
mp_camera_mode_list_get(MPModeList *list)
|
||||
{
|
||||
g_return_val_if_fail(list, NULL);
|
||||
return &list->mode;
|
||||
}
|
||||
|
||||
MPModeList *
|
||||
mp_camera_mode_list_next(MPModeList *list)
|
||||
{
|
||||
g_return_val_if_fail(list, NULL);
|
||||
return list->next;
|
||||
}
|
||||
|
||||
void
|
||||
mp_camera_mode_list_free(MPModeList *list)
|
||||
{
|
||||
while (list) {
|
||||
MPModeList *tmp = list;
|
||||
list = tmp->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
struct int_str_pair {
|
||||
uint32_t value;
|
||||
const char *str;
|
||||
@@ -1010,24 +600,15 @@ struct _MPControlList {
|
||||
MPControlList *next;
|
||||
};
|
||||
|
||||
static int
|
||||
control_fd(MPCamera *camera)
|
||||
{
|
||||
if (camera->subdev_fd != -1) {
|
||||
return camera->subdev_fd;
|
||||
}
|
||||
return camera->video_fd;
|
||||
}
|
||||
|
||||
MPControlList *
|
||||
mp_camera_list_controls(MPCamera *camera)
|
||||
mp_camera_list_controls(libmegapixels_camera *camera)
|
||||
{
|
||||
MPControlList *item = NULL;
|
||||
|
||||
struct v4l2_query_ext_ctrl ctrl = {};
|
||||
ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
|
||||
while (true) {
|
||||
if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
|
||||
if (xioctl(camera->sensor_fd, VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
|
||||
if (errno != EINVAL) {
|
||||
errno_printerr("VIDIOC_QUERY_EXT_CTRL");
|
||||
}
|
||||
@@ -1090,11 +671,13 @@ mp_control_list_free(MPControlList *list)
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_query_control(MPCamera *camera, uint32_t id, MPControl *control)
|
||||
mp_camera_query_control(libmegapixels_camera *camera,
|
||||
uint32_t id,
|
||||
MPControl *control)
|
||||
{
|
||||
struct v4l2_query_ext_ctrl ctrl = {};
|
||||
ctrl.id = id;
|
||||
if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
|
||||
if (xioctl(camera->sensor_fd, VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
|
||||
if (errno != EINVAL) {
|
||||
errno_printerr("VIDIOC_QUERY_EXT_CTRL");
|
||||
}
|
||||
@@ -1121,7 +704,10 @@ mp_camera_query_control(MPCamera *camera, uint32_t id, MPControl *control)
|
||||
}
|
||||
|
||||
static bool
|
||||
control_impl_int32(MPCamera *camera, uint32_t id, int request, int32_t *value)
|
||||
control_impl_int32(libmegapixels_camera *camera,
|
||||
uint32_t id,
|
||||
int request,
|
||||
int32_t *value)
|
||||
{
|
||||
struct v4l2_ext_control ctrl = {};
|
||||
ctrl.id = id;
|
||||
@@ -1133,7 +719,7 @@ control_impl_int32(MPCamera *camera, uint32_t id, int request, int32_t *value)
|
||||
.count = 1,
|
||||
.controls = &ctrl,
|
||||
};
|
||||
if (xioctl(control_fd(camera), request, &ctrls) == -1) {
|
||||
if (xioctl(camera->sensor_fd, request, &ctrls) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1142,7 +728,7 @@ control_impl_int32(MPCamera *camera, uint32_t id, int request, int32_t *value)
|
||||
}
|
||||
|
||||
pid_t
|
||||
mp_camera_control_set_int32_bg(MPCamera *camera, uint32_t id, int32_t v)
|
||||
mp_camera_control_set_int32_bg(libmegapixels_camera *camera, uint32_t id, int32_t v)
|
||||
{
|
||||
struct v4l2_ext_control ctrl = {};
|
||||
ctrl.id = id;
|
||||
@@ -1155,7 +741,7 @@ mp_camera_control_set_int32_bg(MPCamera *camera, uint32_t id, int32_t v)
|
||||
.controls = &ctrl,
|
||||
};
|
||||
|
||||
int fd = control_fd(camera);
|
||||
int fd = camera->sensor_fd;
|
||||
|
||||
// fork only after all the memory has been read
|
||||
pid_t pid = fork();
|
||||
@@ -1174,19 +760,19 @@ mp_camera_control_set_int32_bg(MPCamera *camera, uint32_t id, int32_t v)
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_control_try_int32(MPCamera *camera, uint32_t id, int32_t *v)
|
||||
mp_camera_control_try_int32(libmegapixels_camera *camera, uint32_t id, int32_t *v)
|
||||
{
|
||||
return control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, v);
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_control_set_int32(MPCamera *camera, uint32_t id, int32_t v)
|
||||
mp_camera_control_set_int32(libmegapixels_camera *camera, uint32_t id, int32_t v)
|
||||
{
|
||||
return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &v);
|
||||
}
|
||||
|
||||
int32_t
|
||||
mp_camera_control_get_int32(MPCamera *camera, uint32_t id)
|
||||
mp_camera_control_get_int32(libmegapixels_camera *camera, uint32_t id)
|
||||
{
|
||||
int32_t v = 0;
|
||||
control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v);
|
||||
@@ -1194,7 +780,7 @@ mp_camera_control_get_int32(MPCamera *camera, uint32_t id)
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_control_try_boolean(MPCamera *camera, uint32_t id, bool *v)
|
||||
mp_camera_control_try_boolean(libmegapixels_camera *camera, uint32_t id, bool *v)
|
||||
{
|
||||
int32_t value = *v;
|
||||
bool s = control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, &value);
|
||||
@@ -1203,14 +789,14 @@ mp_camera_control_try_boolean(MPCamera *camera, uint32_t id, bool *v)
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_control_set_bool(MPCamera *camera, uint32_t id, bool v)
|
||||
mp_camera_control_set_bool(libmegapixels_camera *camera, uint32_t id, bool v)
|
||||
{
|
||||
int32_t value = v;
|
||||
return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &value);
|
||||
}
|
||||
|
||||
bool
|
||||
mp_camera_control_get_bool(MPCamera *camera, uint32_t id)
|
||||
mp_camera_control_get_bool(libmegapixels_camera *camera, uint32_t id)
|
||||
{
|
||||
int32_t v = false;
|
||||
control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v);
|
||||
@@ -1218,7 +804,7 @@ mp_camera_control_get_bool(MPCamera *camera, uint32_t id)
|
||||
}
|
||||
|
||||
pid_t
|
||||
mp_camera_control_set_bool_bg(MPCamera *camera, uint32_t id, bool v)
|
||||
mp_camera_control_set_bool_bg(libmegapixels_camera *camera, uint32_t id, bool v)
|
||||
{
|
||||
int32_t value = v;
|
||||
return mp_camera_control_set_int32_bg(camera, id, value);
|
||||
|
Reference in New Issue
Block a user