Move remaining device methods

This commit is contained in:
Kamil Trzcinski 2022-04-10 11:58:59 +02:00
parent 33b7062bf1
commit 09c2f6e595
12 changed files with 307 additions and 210 deletions

View File

@ -2,6 +2,7 @@
#include "device/buffer_list.h"
#include "device/hw/device.h"
#include "device/hw/v4l2.h"
#include <pthread.h>
pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER;

View File

@ -51,7 +51,8 @@ camera_t *camera_open(camera_options_t *options)
camera->camera->allow_dma = false;
}
device_set_pad_format(camera->camera, camera->options.width, camera->options.height, 0);
// TODO: mpad format
// device_set_pad_format(camera->camera, camera->options.width, camera->options.height, 0);
if (device_open_buffer_list(camera->camera, true, camera->options.width, camera->options.height, camera->options.format, 0, camera->options.nbufs, true) < 0) {
goto error;
@ -120,14 +121,15 @@ int camera_set_params(camera_t *camera)
// DEVICE_SET_OPTION(camera->isp_srgb, BLUE_BALANCE, 1472);
// DEVICE_SET_OPTION(camera->isp_srgb, DIGITAL_GAIN, 1007);
DEVICE_SET_OPTION2(camera->codec_jpeg, JPEG, COMPRESSION_QUALITY, 80);
device_set_option_string(camera->codec_jpeg, "compression_quality", "80");
DEVICE_SET_OPTION2(camera->codec_h264, MPEG_VIDEO, BITRATE, 5000 * 1000);
DEVICE_SET_OPTION2(camera->codec_h264, MPEG_VIDEO, H264_I_PERIOD, 30);
DEVICE_SET_OPTION2(camera->codec_h264, MPEG_VIDEO, H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
DEVICE_SET_OPTION2(camera->codec_h264, MPEG_VIDEO, REPEAT_SEQ_HEADER, 1);
DEVICE_SET_OPTION2(camera->codec_h264, MPEG_VIDEO, H264_MIN_QP, 16);
DEVICE_SET_OPTION2(camera->codec_h264, MPEG_VIDEO, H264_MIN_QP, 32);
device_set_option_string(camera->codec_h264, "video_bitrate_mode", "0");
device_set_option_string(camera->codec_h264, "video_bitrate", "5000000");
device_set_option_string(camera->codec_h264, "h264_i_frame_period", "30");
device_set_option_string(camera->codec_h264, "h264_level", "11");
device_set_option_string(camera->codec_h264, "h264_profile", "4");
device_set_option_string(camera->codec_h264, "h264_minimum_qp_value", "16");
device_set_option_string(camera->codec_h264, "h264_maximum_qp_value", "32");
return 0;
}

View File

@ -2,32 +2,22 @@
#include "device/buffer.h"
#include "device/buffer_list.h"
#include "device/hw/v4l2.h"
#include "opts/opts.h"
device_t *device_open(const char *name, const char *path, device_hw_t *hw) {
device_t *dev = calloc(1, sizeof(device_t));
dev->name = strdup(name);
dev->path = strdup(path);
dev->hw = hw;
dev->fd = open(path, O_RDWR|O_NONBLOCK);
dev->fd = -1;
dev->subdev_fd = -1;
dev->allow_dma = true;
if(dev->fd < 0) {
if (dev->hw->device_open(dev) < 0) {
E_LOG_ERROR(dev, "Can't open device: %s", path);
}
E_LOG_DEBUG(dev, "Querying device capabilities ...");
struct v4l2_capability v4l2_cap;
E_XIOCTL(dev, dev->fd, VIDIOC_QUERYCAP, &v4l2_cap, "Can't query device capabilities");
if (!(v4l2_cap.capabilities & V4L2_CAP_STREAMING)) {
E_LOG_ERROR(dev, "Device doesn't support streaming IO");
}
strcpy(dev->bus_info, v4l2_cap.bus_info);
}
E_LOG_INFO(dev, "Device path=%s fd=%d opened", dev->path, dev->fd);
dev->subdev_fd = device_open_v4l2_subdev(dev, 0);
return dev;
error:
@ -50,14 +40,7 @@ void device_close(device_t *dev) {
dev->output_list = NULL;
}
if (dev->subdev_fd >= 0) {
close(dev->subdev_fd);
}
if(dev->fd >= 0) {
close(dev->fd);
}
dev->hw->device_close(dev);
free(dev->name);
free(dev->path);
free(dev);
@ -141,11 +124,14 @@ int device_open_buffer_list_capture(device_t *dev, buffer_list_t *output_list, f
int device_set_stream(device_t *dev, bool do_on)
{
// TODO: support events
#if 0
struct v4l2_event_subscription sub = {0};
sub.type = V4L2_EVENT_SOURCE_CHANGE;
E_LOG_DEBUG(dev, "Subscribing to DV-timings events ...");
xioctl(dev_name(dev), dev->fd, do_on ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT, &sub);
#endif
if (dev->capture_list) {
if (buffer_list_set_stream(dev->capture_list, do_on) < 0) {
@ -162,23 +148,11 @@ int device_set_stream(device_t *dev, bool do_on)
return 0;
}
int device_set_decoder_start(device_t *dev, bool do_on)
{
struct v4l2_decoder_cmd cmd = {0};
cmd.cmd = do_on ? V4L2_DEC_CMD_START : V4L2_DEC_CMD_STOP;
E_LOG_DEBUG(dev, "Setting decoder state %s...", do_on ? "Start" : "Stop");
E_XIOCTL(dev, dev->fd, VIDIOC_DECODER_CMD, &cmd, "Cannot set decoder state");
dev->decoder_started = do_on;
return 0;
error:
return -1;
}
int device_consume_event(device_t *dev)
{
// TODO: support events
#if 0
struct v4l2_event event;
if (!dev) {
@ -200,39 +174,69 @@ int device_consume_event(device_t *dev)
return 0;
error:
#endif
return -1;
}
int device_set_decoder_start(device_t *dev, bool do_on)
{
if (!dev || dev->hw->device_set_decoder_start(dev, do_on) < 0)
return -1;
dev->decoder_started = do_on;
return 0;
}
int device_video_force_key(device_t *dev)
{
if (!dev) {
if (!dev || dev->hw->device_video_force_key(dev) < 0)
return -1;
}
struct v4l2_control ctl = {0};
ctl.id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME;
ctl.value = 1;
E_LOG_DEBUG(dev, "Forcing keyframe ...");
E_XIOCTL(dev, dev->fd, VIDIOC_S_CTRL, &ctl, "Can't force keyframe");
return 0;
error:
return -1;
}
int device_set_fps(device_t *dev, int desired_fps)
{
struct v4l2_streamparm setfps = {0};
if (!dev || dev->hw->device_set_fps(dev, desired_fps) < 0)
return -1;
return 0;
}
int device_set_option_string(device_t *dev, const char *key, const char *value)
{
if (!dev) {
return -1;
}
setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
setfps.parm.output.timeperframe.numerator = 1;
setfps.parm.output.timeperframe.denominator = desired_fps;
E_LOG_DEBUG(dev, "Configuring FPS ...");
E_XIOCTL(dev, dev->fd, VIDIOC_S_PARM, &setfps, "Can't set FPS");
return 0;
error:
return -1;
return dev->hw->device_set_option(dev, key, value);
}
void device_set_option_list(device_t *dev, const char *option_list)
{
if (!dev || !option_list || !option_list[0]) {
return;
}
char *start = strdup(option_list);
char *string = start;
char *option;
while (option = strsep(&string, OPTION_VALUE_LIST_SEP)) {
char *value = option;
char *key = strsep(&value, "=");
if (value) {
device_set_option_string(dev, key, value);
} else {
E_LOG_INFO(dev, "Missing 'key=value' for '%s'", option);
continue;
}
// consume all separators
while (strsep(&value, "="));
}
free(start);
}

View File

@ -10,6 +10,13 @@ typedef struct device_s device_t;
struct pollfd;
typedef struct device_hw_s {
int (*device_open)(device_t *dev);
void (*device_close)(device_t *dev);
int (*device_set_decoder_start)(device_t *dev, bool do_on);
int (*device_video_force_key)(device_t *dev);
int (*device_set_fps)(device_t *dev, int desired_fps);
int (*device_set_option)(device_t *dev, const char *key, const char *value);
int (*buffer_open)(buffer_t *buf);
void (*buffer_close)(buffer_t *buf);
int (*buffer_enqueue)(buffer_t *buf, const char *who);
@ -39,9 +46,6 @@ typedef struct device_s {
} device_t;
device_t *device_open(const char *name, const char *path, device_hw_t *hw);
device_t *device_v4l2_open(const char *name, const char *path);
int device_open_media_device(device_t *dev);
int device_open_v4l2_subdev(device_t *dev, int subdev);
void device_close(device_t *device);
int device_open_buffer_list(device_t *dev, bool do_capture, unsigned width, unsigned height, unsigned format, unsigned bytesperline, int nbufs, bool do_mmap);
@ -54,16 +58,7 @@ int device_set_decoder_start(device_t *dev, bool do_on);
int device_video_force_key(device_t *dev);
int device_set_fps(device_t *dev, int desired_fps);
int device_set_pad_format(device_t *device, unsigned width, unsigned height, unsigned format);
int device_set_option(device_t *dev, const char *name, uint32_t id, int32_t value);
int device_set_option_string(device_t *dev, const char *option);
int device_set_option_string(device_t *dev, const char *option, const char *value);
void device_set_option_list(device_t *dev, const char *option_list);
#define DEVICE_SET_OPTION(dev, name, value) \
device_set_option(dev, #name, V4L2_CID_##name, value)
#define DEVICE_SET_OPTION2(dev, type, name, value) \
device_set_option(dev, #name, V4L2_CID_##type##_##name, value)
#define DEVICE_SET_OPTION2_FATAL(dev, type, name, value) \
do { if (DEVICE_SET_OPTION2(dev, type, name, value) < 0) return -1; } while(0)
device_t *device_v4l2_open(const char *name, const char *path);

View File

@ -1,28 +1,4 @@
#include "device/hw/v4l2.h"
int xioctl(const char *name, int fd, int request, void *arg)
{
int retries = XIOCTL_RETRIES;
int retval = -1;
do {
retval = ioctl(fd, request, arg);
} while (
retval
&& retries--
&& (
errno == EINTR
|| errno == EAGAIN
|| errno == ETIMEDOUT
)
);
// cppcheck-suppress knownConditionTrueFalse
if (retval && retries <= 0) {
E_LOG_PERROR(NULL, "%s: ioctl(%08x) retried %u times; giving up", name, request, XIOCTL_RETRIES);
}
return retval;
}
#include "v4l2.h"
fourcc_string fourcc_to_string(unsigned format)
{
@ -43,34 +19,3 @@ fourcc_string fourcc_to_string(unsigned format)
*ptr++ = 0;
return fourcc;
}
static size_t align_size(size_t size, size_t to)
{
return ((size + (to - 1)) & ~(to - 1));
}
unsigned fourcc_to_stride(unsigned width, unsigned format)
{
switch (format) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_RGB565:
return align_size(width * 2, 32);
case V4L2_PIX_FMT_YUV420:
return align_size(width * 3 / 2, 32);
case V4L2_PIX_FMT_RGB24:
return align_size(width * 3, 32);
case V4L2_PIX_FMT_SRGGB10P:
return align_size(width * 5 / 4, 32);
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_H264:
return 0;
default:
E_LOG_PERROR(NULL, "Unknown format: %s", fourcc_to_string(format).buf);
}
}

View File

@ -21,23 +21,8 @@
#include "opts/log.h"
#ifndef CFG_XIOCTL_RETRIES
# define CFG_XIOCTL_RETRIES 4
#endif
#define XIOCTL_RETRIES ((unsigned)(CFG_XIOCTL_RETRIES))
typedef struct {
char buf[10];
} fourcc_string;
fourcc_string fourcc_to_string(unsigned format);
unsigned fourcc_to_stride(unsigned width, unsigned format);
int xioctl(const char *name, int fd, int request, void *arg);
#define E_XIOCTL(dev, _fd, _request, _value, _msg, ...) do { \
int ret; \
if ((ret = xioctl(dev_name(dev), _fd, _request, _value)) < 0) { \
E_LOG_ERROR(dev, "xioctl(ret=%d): " _msg, ret, ##__VA_ARGS__); \
} \
} while(0)

View File

@ -2,18 +2,88 @@
#include "device/hw/v4l2.h"
#include "device/hw/device.h"
device_hw_t v4l2_device_hw = {
.buffer_open = v4l2_buffer_open,
.buffer_close = v4l2_buffer_close,
.buffer_enqueue = v4l2_buffer_enqueue,
.buffer_list_dequeue = v4l2_buffer_list_dequeue,
.buffer_list_pollfd = v4l2_buffer_list_pollfd,
.buffer_list_set_format = v4l2_buffer_list_set_format,
.buffer_list_set_buffers = v4l2_buffer_list_set_buffers,
.buffer_list_set_stream = v4l2_buffer_list_set_stream
};
device_t *device_v4l2_open(const char *name, const char *path)
int v4l2_device_open(device_t *dev)
{
return device_open(name, path, &v4l2_device_hw);
dev->fd = -1;
dev->subdev_fd = -1;
dev->fd = open(dev->path, O_RDWR|O_NONBLOCK);
if (dev->fd < 0) {
E_LOG_ERROR(dev, "Can't open device: %s", dev->path);
goto error;
}
E_LOG_DEBUG(dev, "Querying device capabilities ...");
struct v4l2_capability v4l2_cap;
E_XIOCTL(dev, dev->fd, VIDIOC_QUERYCAP, &v4l2_cap, "Can't query device capabilities");
if (!(v4l2_cap.capabilities & V4L2_CAP_STREAMING)) {
E_LOG_ERROR(dev, "Device doesn't support streaming IO");
}
strcpy(dev->bus_info, v4l2_cap.bus_info);
dev->subdev_fd = v4l2_device_open_v4l2_subdev(dev, 0);
return 0;
error:
return -1;
}
void v4l2_device_close(device_t *dev)
{
if (dev->subdev_fd >= 0) {
close(dev->subdev_fd);
}
if(dev->fd >= 0) {
close(dev->fd);
}
}
int v4l2_device_set_decoder_start(device_t *dev, bool do_on)
{
struct v4l2_decoder_cmd cmd = {0};
cmd.cmd = do_on ? V4L2_DEC_CMD_START : V4L2_DEC_CMD_STOP;
E_LOG_DEBUG(dev, "Setting decoder state %s...", do_on ? "Start" : "Stop");
E_XIOCTL(dev, dev->fd, VIDIOC_DECODER_CMD, &cmd, "Cannot set decoder state");
return 0;
error:
return -1;
}
int v4l2_device_video_force_key(device_t *dev)
{
struct v4l2_control ctl = {0};
ctl.id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME;
ctl.value = 1;
E_LOG_DEBUG(dev, "Forcing keyframe ...");
E_XIOCTL(dev, dev->fd, VIDIOC_S_CTRL, &ctl, "Can't force keyframe");
return 0;
error:
return -1;
}
int v4l2_device_set_fps(device_t *dev, int desired_fps)
{
struct v4l2_streamparm setfps = {0};
if (!dev) {
return -1;
}
setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
setfps.parm.output.timeperframe.numerator = 1;
setfps.parm.output.timeperframe.denominator = desired_fps;
E_LOG_DEBUG(dev, "Configuring FPS ...");
E_XIOCTL(dev, dev->fd, VIDIOC_S_PARM, &setfps, "Can't set FPS");
return 0;
error:
return -1;
}

27
device/v4l2/device_hw.c Normal file
View File

@ -0,0 +1,27 @@
#include "device/v4l2/v4l2.h"
#include "device/hw/v4l2.h"
#include "device/hw/device.h"
device_hw_t v4l2_device_hw = {
.device_open = v4l2_device_open,
.device_close = v4l2_device_close,
.device_set_decoder_start = v4l2_device_set_decoder_start,
.device_video_force_key = v4l2_device_video_force_key,
.device_set_fps = v4l2_device_set_fps,
.device_set_option = v4l2_device_set_option,
.buffer_open = v4l2_buffer_open,
.buffer_close = v4l2_buffer_close,
.buffer_enqueue = v4l2_buffer_enqueue,
.buffer_list_dequeue = v4l2_buffer_list_dequeue,
.buffer_list_pollfd = v4l2_buffer_list_pollfd,
.buffer_list_set_format = v4l2_buffer_list_set_format,
.buffer_list_set_buffers = v4l2_buffer_list_set_buffers,
.buffer_list_set_stream = v4l2_buffer_list_set_stream
};
device_t *device_v4l2_open(const char *name, const char *path)
{
return device_open(name, path, &v4l2_device_hw);
}

View File

@ -1,3 +1,4 @@
#include "device/v4l2/v4l2.h"
#include "device/hw/device.h"
#include "device/hw/v4l2.h"
@ -8,7 +9,7 @@
#include <sys/sysmacros.h>
#include <linux/media.h>
int device_open_media_device(device_t *dev)
int v4l2_device_open_media_device(device_t *dev)
{
struct stat st;
if (fstat(dev->fd, &st) < 0) {
@ -49,13 +50,13 @@ error:
return ret;
}
int device_open_v4l2_subdev(device_t *dev, int subdev)
int v4l2_device_open_v4l2_subdev(device_t *dev, int subdev)
{
int media_fd = -1;
unsigned int last_id = 0;
int ret = -1;
media_fd = device_open_media_device(dev);
media_fd = v4l2_device_open_media_device(dev);
if (media_fd < 0) {
E_LOG_ERROR(dev, "Cannot find media controller");
}
@ -106,7 +107,7 @@ error:
return ret;
}
int device_set_pad_format(device_t *dev, unsigned width, unsigned height, unsigned format)
int v4l2_device_set_pad_format(device_t *dev, unsigned width, unsigned height, unsigned format)
{
struct v4l2_subdev_format fmt = {0};

View File

@ -1,10 +1,10 @@
#include "device/hw/device.h"
#include "device/v4l2/v4l2.h"
#include "device/hw/v4l2.h"
#include "opts/opts.h"
#include "device/hw/device.h"
#include <ctype.h>
int device_set_option(device_t *dev, const char *name, uint32_t id, int32_t value)
int v4l2_device_set_option_by_id(device_t *dev, const char *name, uint32_t id, int32_t value)
{
struct v4l2_control ctl = {0};
@ -21,7 +21,7 @@ error:
return -1;
}
void device_option_normalize_name(char *in)
void v4l2_device_option_normalize_name(char *in)
{
char *out = in;
@ -39,7 +39,7 @@ void device_option_normalize_name(char *in)
*out++ = 0;
}
static int device_set_option_string_fd_by_id(device_t *dev, int fd, uint32_t *id, char *name, char *value)
static int v4l2_device_set_option_string_fd_iter_id(device_t *dev, int fd, uint32_t *id, char *name, char *value)
{
struct v4l2_query_ext_ctrl qctrl = { .id = *id };
void *data = NULL;
@ -50,7 +50,7 @@ static int device_set_option_string_fd_by_id(device_t *dev, int fd, uint32_t *id
}
*id = qctrl.id;
device_option_normalize_name(qctrl.name);
v4l2_device_option_normalize_name(qctrl.name);
if (strcmp(qctrl.name, name) != 0)
return 0;
@ -131,61 +131,42 @@ error:
return -1;
}
static int device_set_option_string_fd(device_t *dev, int fd, char *name, char *value)
static int v4l2_device_set_option_string_fd(device_t *dev, int fd, char *name, char *value)
{
int ret = 0;
uint32_t id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
while ((ret = device_set_option_string_fd_by_id(dev, fd, &id, name, value)) == 0 && id) {
while ((ret = v4l2_device_set_option_string_fd_iter_id(dev, fd, &id, name, value)) == 0 && id) {
id |= V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
}
return ret;
}
int device_set_option_string(device_t *dev, const char *option)
int v4l2_device_set_option(device_t *dev, const char *key, const char *value)
{
int ret = -1;
char *name = strdup(option);
strcpy(name, option);
char *keyp = strdup(key);
char *valuep = strdup(value);
char *value = strchr(name, '=');
if (!value) {
E_LOG_ERROR(dev, "Missing 'key=value': '%s'", option);
}
*value++ = 0;
int ret = 0;
device_option_normalize_name(name);
v4l2_device_option_normalize_name(keyp);
if (dev->subdev_fd >= 0)
ret = device_set_option_string_fd(dev, dev->subdev_fd, name, value);
ret = v4l2_device_set_option_string_fd(dev, dev->subdev_fd, keyp, valuep);
if (ret <= 0)
ret = device_set_option_string_fd(dev, dev->fd, name, value);
if (ret == 0)
E_LOG_ERROR(dev, "The '%s' was failed to find.", option);
else if (ret < 0)
E_LOG_ERROR(dev, "The '%s' did fail to be set.", option);
ret = v4l2_device_set_option_string_fd(dev, dev->fd, keyp, valuep);
ret = 0;
free(keyp);
free(valuep);
if (ret == 0)
E_LOG_ERROR(dev, "The '%s=%s' was failed to find.", key, value);
else if (ret < 0)
E_LOG_ERROR(dev, "The '%s=%s' did fail to be set.", key, value);
return 0;
error:
free(name);
return ret;
return -1;
}
void device_set_option_list(device_t *dev, const char *option_list)
{
if (!dev || !option_list || !option_list[0]) {
return;
}
char *start = strdup(option_list);
char *string = start;
char *option;
while (option = strsep(&string, OPTION_VALUE_LIST_SEP)) {
device_set_option_string(dev, option);
}
free(start);
}

59
device/v4l2/v4l2.c Normal file
View File

@ -0,0 +1,59 @@
#include "device/v4l2/v4l2.h"
#include <linux/videodev2.h>
#include <linux/v4l2-subdev.h>
int xioctl(const char *name, int fd, int request, void *arg)
{
int retries = XIOCTL_RETRIES;
int retval = -1;
do {
retval = ioctl(fd, request, arg);
} while (
retval
&& retries--
&& (
errno == EINTR
|| errno == EAGAIN
|| errno == ETIMEDOUT
)
);
// cppcheck-suppress knownConditionTrueFalse
if (retval && retries <= 0) {
E_LOG_PERROR(NULL, "%s: ioctl(%08x) retried %u times; giving up", name, request, XIOCTL_RETRIES);
}
return retval;
}
static size_t align_size(size_t size, size_t to)
{
return ((size + (to - 1)) & ~(to - 1));
}
unsigned fourcc_to_stride(unsigned width, unsigned format)
{
switch (format) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_RGB565:
return align_size(width * 2, 32);
case V4L2_PIX_FMT_YUV420:
return align_size(width * 3 / 2, 32);
case V4L2_PIX_FMT_RGB24:
return align_size(width * 3, 32);
case V4L2_PIX_FMT_SRGGB10P:
return align_size(width * 5 / 4, 32);
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_H264:
return 0;
default:
E_LOG_PERROR(NULL, "Unknown format: %s", fourcc_to_string(format).buf);
}
}

View File

@ -5,8 +5,16 @@
typedef struct buffer_s buffer_t;
typedef struct buffer_list_s buffer_list_t;
typedef struct device_s device_t;
struct pollfd;
int v4l2_device_open(device_t *dev);
void v4l2_device_close(device_t *dev);
int v4l2_device_set_decoder_start(device_t *dev, bool do_on);
int v4l2_device_video_force_key(device_t *dev);
int v4l2_device_set_fps(device_t *dev, int desired_fps);
int v4l2_device_set_option(device_t *dev, const char *key, const char *value);
int v4l2_buffer_open(buffer_t *buf);
void v4l2_buffer_close(buffer_t *buf);
int v4l2_buffer_enqueue(buffer_t *buf, const char *who);
@ -17,3 +25,22 @@ int v4l2_buffer_list_pollfd(buffer_list_t *buf_list, struct pollfd *pollfd, bool
int v4l2_buffer_list_set_format(buffer_list_t *buf_list, unsigned width, unsigned height, unsigned format, unsigned bytesperline);
int v4l2_buffer_list_set_buffers(buffer_list_t *buf_list, int nbufs);
int v4l2_buffer_list_set_stream(buffer_list_t *buf_list, bool do_on);
int v4l2_device_open_media_device(device_t *dev);
int v4l2_device_open_v4l2_subdev(device_t *dev, int subdev);
int v4l2_device_set_pad_format(device_t *dev, unsigned width, unsigned height, unsigned format);
#ifndef CFG_XIOCTL_RETRIES
# define CFG_XIOCTL_RETRIES 4
#endif
#define XIOCTL_RETRIES ((unsigned)(CFG_XIOCTL_RETRIES))
unsigned fourcc_to_stride(unsigned width, unsigned format);
int xioctl(const char *name, int fd, int request, void *arg);
#define E_XIOCTL(dev, _fd, _request, _value, _msg, ...) do { \
int ret; \
if ((ret = xioctl(dev_name(dev), _fd, _request, _value)) < 0) { \
E_LOG_ERROR(dev, "xioctl(ret=%d): " _msg, ret, ##__VA_ARGS__); \
} \
} while(0)