Move remaining device
methods
This commit is contained in:
parent
33b7062bf1
commit
09c2f6e595
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
27
device/v4l2/device_hw.c
Normal 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);
|
||||
}
|
@ -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};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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);
|
||||
return -1;
|
||||
}
|
59
device/v4l2/v4l2.c
Normal file
59
device/v4l2/v4l2.c
Normal 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);
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user