blob: c09cd987d2dd9667e218d64aeb22ac529111893a [file] [log] [blame]
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* V4L2 C helper header providing wrappers to simplify access to the various
* v4l2 functions.
*
* Copyright 2014-2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*/
#ifndef _V4L_HELPERS_H_
#define _V4L_HELPERS_H_
#include <linux/videodev2.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct v4l_fd {
int fd;
struct v4l2_capability cap;
char devname[128];
__u32 type;
__u32 caps;
unsigned int trace;
bool direct;
bool have_query_ext_ctrl;
bool have_ext_ctrls;
bool have_next_ctrl;
bool have_selection;
bool is_subdev;
bool is_media;
int (*open)(struct v4l_fd *f, const char *file, int oflag, ...);
int (*close)(struct v4l_fd *f);
int (*ioctl)(struct v4l_fd *f, unsigned long cmd, ...);
ssize_t (*read)(struct v4l_fd *f, void *buffer, size_t n);
ssize_t (*write)(struct v4l_fd *f, const void *buffer, size_t n);
void *(*mmap)(void *addr, size_t length, int prot, int flags,
struct v4l_fd *f, off_t offset);
int (*munmap)(struct v4l_fd *f, void *addr, size_t length);
};
#ifdef __LIBV4L2_H
static inline int v4l_wrap_open(struct v4l_fd *f, const char *file, int oflag, ...)
{
return f->direct ? open(file, oflag) : v4l2_open(file, oflag);
}
static inline int v4l_wrap_close(struct v4l_fd *f)
{
int ret = f->direct ? close(f->fd) : v4l2_close(f->fd);
f->fd = -1;
return ret;
}
static inline ssize_t v4l_wrap_read(struct v4l_fd *f, void *buffer, size_t n)
{
return f->direct ? read(f->fd, buffer, n) : v4l2_read(f->fd, buffer, n);
}
static inline ssize_t v4l_wrap_write(struct v4l_fd *f, const void *buffer, size_t n)
{
return f->direct ? write(f->fd, buffer, n) : v4l2_write(f->fd, buffer, n);
}
static inline int v4l_wrap_ioctl(struct v4l_fd *f, unsigned long cmd, ...)
{
void *arg;
va_list ap;
va_start(ap, cmd);
arg = va_arg(ap, void *);
va_end(ap);
return f->direct ? ioctl(f->fd, cmd, arg) : v4l2_ioctl(f->fd, cmd, arg);
}
static inline void *v4l_wrap_mmap(void *start, size_t length, int prot, int flags,
struct v4l_fd *f, off_t offset)
{
return f->direct ? mmap(start, length, prot, flags, f->fd, offset) :
v4l2_mmap(start, length, prot, flags, f->fd, offset);
}
static inline int v4l_wrap_munmap(struct v4l_fd *f, void *start, size_t length)
{
return f->direct ? munmap(start, length) : v4l2_munmap(start, length);
}
static inline bool v4l_fd_g_direct(const struct v4l_fd *f)
{
return f->direct;
}
static inline void v4l_fd_s_direct(struct v4l_fd *f, bool direct)
{
if (!f->is_subdev && !f->is_media)
f->direct = direct;
}
#else
static inline int v4l_wrap_open(struct v4l_fd *f, const char *file, int oflag, ...)
{
return open(file, oflag);
}
static inline int v4l_wrap_close(struct v4l_fd *f)
{
int ret = close(f->fd);
f->fd = -1;
return ret;
}
static inline ssize_t v4l_wrap_read(struct v4l_fd *f, void *buffer, size_t n)
{
return read(f->fd, buffer, n);
}
static inline ssize_t v4l_wrap_write(struct v4l_fd *f, const void *buffer, size_t n)
{
return write(f->fd, buffer, n);
}
static inline int v4l_wrap_ioctl(struct v4l_fd *f, unsigned long cmd, ...)
{
void *arg;
va_list ap;
va_start(ap, cmd);
arg = va_arg(ap, void *);
va_end(ap);
return ioctl(f->fd, cmd, arg);
}
static inline void *v4l_wrap_mmap(void *start, size_t length, int prot, int flags,
struct v4l_fd *f, off_t offset)
{
return mmap(start, length, prot, flags, f->fd, offset);
}
static inline int v4l_wrap_munmap(struct v4l_fd *f, void *start, size_t length)
{
return munmap(start, length);
}
static inline bool v4l_fd_g_direct(const struct v4l_fd *f)
{
return true;
}
static inline void v4l_fd_s_direct(struct v4l_fd *f, bool direct)
{
}
#endif
static inline void v4l_fd_init(struct v4l_fd *f)
{
memset(f, 0, sizeof(*f));
f->fd = -1;
f->is_subdev = false;
f->is_media = false;
f->open = v4l_wrap_open;
f->close = v4l_wrap_close;
f->ioctl = v4l_wrap_ioctl;
f->read = v4l_wrap_read;
f->write = v4l_wrap_write;
f->mmap = v4l_wrap_mmap;
f->munmap = v4l_wrap_munmap;
}
static inline bool v4l_fd_is_subdev(const struct v4l_fd *f)
{
return f->is_subdev;
}
static inline bool v4l_fd_is_media(const struct v4l_fd *f)
{
return f->is_media;
}
static inline bool v4l_fd_is_v4l2(const struct v4l_fd *f)
{
return !f->is_subdev && !f->is_media;
}
static inline unsigned int v4l_fd_g_trace(const struct v4l_fd *f)
{
return f->trace;
}
static inline void v4l_fd_s_trace(struct v4l_fd *f, unsigned int trace)
{
f->trace = trace;
}
static inline int v4l_named_ioctl(struct v4l_fd *f,
const char *cmd_name, unsigned long cmd, void *arg)
{
int retval;
int e;
retval = f->ioctl(f, cmd, arg);
e = retval == 0 ? 0 : errno;
if (f->trace >= (e ? 1 : 2))
fprintf(stderr, "\t\t%s returned %d (%s)\n",
cmd_name, retval, strerror(e));
return retval == -1 ? e : (retval ? -1 : 0);
}
#define v4l_ioctl(f, cmd, arg) v4l_named_ioctl(f, #cmd, cmd, arg)
static inline void *v4l_mmap(struct v4l_fd *f, size_t length, off_t offset)
{
return f->mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, f, offset);
}
static inline int v4l_munmap(struct v4l_fd *f, void *start, size_t length)
{
return f->munmap(f, start, length);
}
static inline ssize_t v4l_read(struct v4l_fd *f, void *buffer, size_t n)
{
return f->read(f, buffer, n);
}
static inline ssize_t v4l_write(struct v4l_fd *f, const void *buffer, size_t n)
{
return f->write(f, buffer, n);
}
static inline int v4l_close(struct v4l_fd *f)
{
int res = f->close(f);
f->caps = f->type = 0;
f->fd = -1;
return res;
}
static inline int v4l_querycap(struct v4l_fd *f, struct v4l2_capability *cap)
{
return v4l_ioctl(f, VIDIOC_QUERYCAP, cap);
}
static inline __u32 v4l_capability_g_caps(const struct v4l2_capability *cap)
{
return (cap->capabilities & V4L2_CAP_DEVICE_CAPS) ?
cap->device_caps : cap->capabilities;
}
static inline __u32 v4l_g_type(const struct v4l_fd *f)
{
return f->type;
}
static inline void v4l_s_type(struct v4l_fd *f, __u32 type)
{
f->type = type;
}
static inline __u32 v4l_g_selection_type(const struct v4l_fd *f)
{
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
return V4L2_BUF_TYPE_VIDEO_OUTPUT;
return f->type;
}
static inline __u32 v4l_g_caps(const struct v4l_fd *f)
{
return f->caps;
}
static inline bool v4l_has_vid_cap(const struct v4l_fd *f)
{
return v4l_g_caps(f) & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE |
V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE);
}
static inline bool v4l_has_vid_out(const struct v4l_fd *f)
{
return v4l_g_caps(f) & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE);
}
static inline bool v4l_has_vid_m2m(const struct v4l_fd *f)
{
return v4l_g_caps(f) & (V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE);
}
static inline bool v4l_has_vid_mplane(const struct v4l_fd *f)
{
return v4l_g_caps(f) & (V4L2_CAP_VIDEO_CAPTURE_MPLANE |
V4L2_CAP_VIDEO_OUTPUT_MPLANE |
V4L2_CAP_VIDEO_M2M_MPLANE);
}
static inline bool v4l_has_overlay_cap(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_VIDEO_OVERLAY;
}
static inline bool v4l_has_overlay_out(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
}
static inline bool v4l_has_raw_vbi_cap(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_VBI_CAPTURE;
}
static inline bool v4l_has_sliced_vbi_cap(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_SLICED_VBI_CAPTURE;
}
static inline bool v4l_has_vbi_cap(const struct v4l_fd *f)
{
return v4l_has_raw_vbi_cap(f) || v4l_has_sliced_vbi_cap(f);
}
static inline bool v4l_has_raw_vbi_out(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_VBI_OUTPUT;
}
static inline bool v4l_has_sliced_vbi_out(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_SLICED_VBI_OUTPUT;
}
static inline bool v4l_has_vbi_out(const struct v4l_fd *f)
{
return v4l_has_raw_vbi_out(f) || v4l_has_sliced_vbi_out(f);
}
static inline bool v4l_has_vbi(const struct v4l_fd *f)
{
return v4l_has_vbi_cap(f) || v4l_has_vbi_out(f);
}
static inline bool v4l_has_radio_rx(const struct v4l_fd *f)
{
return (v4l_g_caps(f) & V4L2_CAP_RADIO) &&
(v4l_g_caps(f) & V4L2_CAP_TUNER);
}
static inline bool v4l_has_radio_tx(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_MODULATOR;
}
static inline bool v4l_has_rds_cap(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_RDS_CAPTURE;
}
static inline bool v4l_has_rds_out(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_RDS_OUTPUT;
}
static inline bool v4l_has_sdr_cap(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_SDR_CAPTURE;
}
static inline bool v4l_has_sdr_out(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_SDR_OUTPUT;
}
static inline bool v4l_has_meta_cap(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_META_CAPTURE;
}
static inline bool v4l_has_meta_out(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_META_OUTPUT;
}
static inline bool v4l_has_touch(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_TOUCH;
}
static inline bool v4l_has_hwseek(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_HW_FREQ_SEEK;
}
static inline bool v4l_has_rw(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_READWRITE;
}
static inline bool v4l_has_streaming(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_STREAMING;
}
static inline bool v4l_has_ext_pix_format(const struct v4l_fd *f)
{
return v4l_g_caps(f) & V4L2_CAP_EXT_PIX_FORMAT;
}
static inline __u32 v4l_determine_type(const struct v4l_fd *f)
{
if (v4l_has_vid_mplane(f))
return v4l_has_vid_cap(f) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
if (v4l_has_vid_cap(f))
return V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (v4l_has_vid_out(f))
return V4L2_BUF_TYPE_VIDEO_OUTPUT;
if (v4l_has_raw_vbi_cap(f))
return V4L2_BUF_TYPE_VBI_CAPTURE;
if (v4l_has_sliced_vbi_cap(f))
return V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
if (v4l_has_raw_vbi_out(f))
return V4L2_BUF_TYPE_VBI_OUTPUT;
if (v4l_has_sliced_vbi_out(f))
return V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
if (v4l_has_sdr_cap(f))
return V4L2_BUF_TYPE_SDR_CAPTURE;
if (v4l_has_sdr_out(f))
return V4L2_BUF_TYPE_SDR_OUTPUT;
if (v4l_has_meta_cap(f))
return V4L2_BUF_TYPE_META_CAPTURE;
if (v4l_has_meta_out(f))
return V4L2_BUF_TYPE_META_OUTPUT;
return 0;
}
static inline int v4l_s_fd(struct v4l_fd *f, int fd, const char *devname, bool direct)
{
struct v4l2_query_ext_ctrl qec;
struct v4l2_ext_controls ec;
struct v4l2_queryctrl qc;
struct v4l2_selection sel;
if (f->fd >= 0)
f->close(f);
f->fd = fd;
f->direct = direct;
if (fd < 0)
return fd;
memset(&qec, 0, sizeof(qec));
qec.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
memset(&ec, 0, sizeof(ec));
memset(&qc, 0, sizeof(qc));
qc.id = V4L2_CTRL_FLAG_NEXT_CTRL;
memset(&sel, 0, sizeof(sel));
if (f->devname != devname)
strncpy(f->devname, devname, sizeof(f->devname));
f->devname[sizeof(f->devname) - 1] = '\0';
memset(&f->cap, 0, sizeof(f->cap));
if (v4l_querycap(f, &f->cap)) {
v4l_close(f);
return -1;
}
f->is_subdev = false;
f->is_media = false;
f->caps = v4l_capability_g_caps(&f->cap);
f->type = v4l_determine_type(f);
f->have_query_ext_ctrl = v4l_ioctl(f, VIDIOC_QUERY_EXT_CTRL, &qec) == 0;
f->have_ext_ctrls = v4l_ioctl(f, VIDIOC_TRY_EXT_CTRLS, &ec) == 0;
f->have_next_ctrl = v4l_ioctl(f, VIDIOC_QUERYCTRL, &qc) == 0;
sel.type = v4l_g_selection_type(f);
sel.target = sel.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE;
f->have_selection = v4l_ioctl(f, VIDIOC_G_SELECTION, &sel) != ENOTTY;
return f->fd;
}
static inline int v4l_open(struct v4l_fd *f, const char *devname, bool non_blocking)
{
int fd = f->open(f, devname, O_RDWR | (non_blocking ? O_NONBLOCK : 0));
return v4l_s_fd(f, fd, devname, f->direct);
}
static inline int v4l_subdev_s_fd(struct v4l_fd *f, int fd, const char *devname)
{
if (f->fd >= 0)
f->close(f);
f->fd = fd;
f->direct = true;
if (fd < 0)
return fd;
if (f->devname != devname)
strncpy(f->devname, devname, sizeof(f->devname));
f->devname[sizeof(f->devname) - 1] = '\0';
memset(&f->cap, 0, sizeof(f->cap));
f->is_subdev = true;
f->is_media = false;
f->type = 0;
f->have_query_ext_ctrl = false;
f->have_ext_ctrls = false;
f->have_next_ctrl = false;
f->have_selection = false;
return f->fd;
}
static inline int v4l_subdev_open(struct v4l_fd *f, const char *devname, bool non_blocking)
{
int fd = f->open(f, devname, O_RDWR | (non_blocking ? O_NONBLOCK : 0));
return v4l_subdev_s_fd(f, fd, devname);
}
static inline int v4l_media_s_fd(struct v4l_fd *f, int fd, const char *devname)
{
if (f->fd >= 0)
f->close(f);
f->fd = fd;
f->direct = true;
if (fd < 0)
return fd;
if (f->devname != devname)
strncpy(f->devname, devname, sizeof(f->devname));
f->devname[sizeof(f->devname) - 1] = '\0';
memset(&f->cap, 0, sizeof(f->cap));
f->is_subdev = false;
f->is_media = true;
f->type = 0;
f->have_query_ext_ctrl = false;
f->have_ext_ctrls = false;
f->have_next_ctrl = false;
f->have_selection = false;
return f->fd;
}
static inline int v4l_media_open(struct v4l_fd *f, const char *devname, bool non_blocking)
{
int fd = f->open(f, devname, O_RDWR | (non_blocking ? O_NONBLOCK : 0));
return v4l_media_s_fd(f, fd, devname);
}
static inline int v4l_reopen(struct v4l_fd *f, bool non_blocking)
{
f->close(f);
if (f->is_subdev)
return v4l_subdev_open(f, f->devname, non_blocking);
if (f->is_media)
return v4l_media_open(f, f->devname, non_blocking);
return v4l_open(f, f->devname, non_blocking);
}
static inline void v4l_format_init(struct v4l2_format *fmt, unsigned type)
{
memset(fmt, 0, sizeof(*fmt));
fmt->type = type;
if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
fmt->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
}
static inline void v4l_format_s_width(struct v4l2_format *fmt, __u32 width)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
fmt->fmt.pix.width = width;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.width = width;
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
fmt->fmt.win.w.width = width;
break;
}
}
static inline __u32 v4l_format_g_width(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return fmt->fmt.pix.width;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.width;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return fmt->fmt.win.w.width;
default:
return 0;
}
}
static inline void v4l_format_s_height(struct v4l2_format *fmt, __u32 height)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
fmt->fmt.pix.height = height;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.height = height;
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
fmt->fmt.win.w.height = height;
break;
}
}
static inline __u32 v4l_format_g_height(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return fmt->fmt.pix.height;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.height;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return fmt->fmt.win.w.height;
default:
return 0;
}
}
static inline void v4l_format_s_pixelformat(struct v4l2_format *fmt, __u32 pixelformat)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
fmt->fmt.pix.pixelformat = pixelformat;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.pixelformat = pixelformat;
break;
case V4L2_BUF_TYPE_SDR_CAPTURE:
case V4L2_BUF_TYPE_SDR_OUTPUT:
fmt->fmt.sdr.pixelformat = pixelformat;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
fmt->fmt.vbi.sample_format = pixelformat;
break;
case V4L2_BUF_TYPE_META_CAPTURE:
case V4L2_BUF_TYPE_META_OUTPUT:
fmt->fmt.meta.dataformat = pixelformat;
break;
}
}
static inline __u32 v4l_format_g_pixelformat(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return fmt->fmt.pix.pixelformat;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.pixelformat;
case V4L2_BUF_TYPE_SDR_CAPTURE:
case V4L2_BUF_TYPE_SDR_OUTPUT:
return fmt->fmt.sdr.pixelformat;
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
return fmt->fmt.vbi.sample_format;
case V4L2_BUF_TYPE_META_CAPTURE:
case V4L2_BUF_TYPE_META_OUTPUT:
return fmt->fmt.meta.dataformat;
default:
return 0;
}
}
static inline void v4l_format_s_field(struct v4l2_format *fmt, unsigned field)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
fmt->fmt.pix.field = field;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.field = field;
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
fmt->fmt.win.field = field;
break;
}
}
static inline unsigned v4l_format_g_field(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return fmt->fmt.pix.field;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.field;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return fmt->fmt.win.field;
default:
return V4L2_FIELD_NONE;
}
}
static inline unsigned v4l_format_g_first_field(const struct v4l2_format *fmt,
v4l2_std_id std)
{
unsigned field = v4l_format_g_field(fmt);
if (field != V4L2_FIELD_ALTERNATE)
return field;
if (std & V4L2_STD_525_60)
return V4L2_FIELD_BOTTOM;
return V4L2_FIELD_TOP;
}
static inline unsigned v4l_format_g_flds_per_frm(const struct v4l2_format *fmt)
{
unsigned field = v4l_format_g_field(fmt);
if (field == V4L2_FIELD_ALTERNATE ||
field == V4L2_FIELD_TOP || field == V4L2_FIELD_BOTTOM)
return 2;
return 1;
}
static inline void v4l_format_s_frame_height(struct v4l2_format *fmt, __u32 height)
{
if (V4L2_FIELD_HAS_T_OR_B(v4l_format_g_field(fmt)))
height /= 2;
v4l_format_s_height(fmt, height);
}
static inline __u32 v4l_format_g_frame_height(const struct v4l2_format *fmt)
{
__u32 height = v4l_format_g_height(fmt);
if (V4L2_FIELD_HAS_T_OR_B(v4l_format_g_field(fmt)))
return height * 2;
return height;
}
static inline void v4l_format_s_colorspace(struct v4l2_format *fmt,
unsigned colorspace)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
fmt->fmt.pix.colorspace = colorspace;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.colorspace = colorspace;
break;
}
}
static inline unsigned
v4l_format_g_colorspace(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return fmt->fmt.pix.colorspace;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.colorspace;
default:
return 0;
}
}
static inline void v4l_format_s_xfer_func(struct v4l2_format *fmt,
unsigned xfer_func)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
fmt->fmt.pix.xfer_func = xfer_func;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.xfer_func = xfer_func;
break;
}
}
static inline unsigned
v4l_format_g_xfer_func(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return fmt->fmt.pix.xfer_func;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.xfer_func;
default:
return 0;
}
}
static inline void v4l_format_s_ycbcr_enc(struct v4l2_format *fmt,
unsigned ycbcr_enc)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
fmt->fmt.pix.ycbcr_enc = ycbcr_enc;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.ycbcr_enc = ycbcr_enc;
break;
}
}
static inline unsigned
v4l_format_g_ycbcr_enc(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return fmt->fmt.pix.ycbcr_enc;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.ycbcr_enc;
default:
return 0;
}
}
static inline unsigned
v4l_format_g_hsv_enc(const struct v4l2_format *fmt)
{
unsigned hsv_enc = v4l_format_g_ycbcr_enc(fmt);
if (hsv_enc == V4L2_HSV_ENC_180)
return V4L2_HSV_ENC_180;
return hsv_enc;
}
static inline void v4l_format_s_quantization(struct v4l2_format *fmt,
unsigned quantization)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
fmt->fmt.pix.quantization = quantization;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.quantization = quantization;
break;
}
}
static inline unsigned
v4l_format_g_quantization(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return fmt->fmt.pix.quantization;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.quantization;
default:
return 0;
}
}
static inline void v4l_format_s_flags(struct v4l2_format *fmt,
unsigned flags)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
fmt->fmt.pix.flags = flags;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.flags = flags;
break;
}
}
static inline unsigned
v4l_format_g_flags(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return fmt->fmt.pix.flags;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.flags;
default:
return 0;
}
}
static inline void v4l_format_s_num_planes(struct v4l2_format *fmt, __u8 num_planes)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.num_planes = num_planes;
break;
}
}
static inline __u8
v4l_format_g_num_planes(const struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.num_planes;
default:
return 1;
}
}
static inline void v4l_format_s_bytesperline(struct v4l2_format *fmt,
unsigned plane, __u32 bytesperline)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
if (plane == 0)
fmt->fmt.pix.bytesperline = bytesperline;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.plane_fmt[plane].bytesperline = bytesperline;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
/* This assumes V4L2_PIX_FMT_GREY which is always the case */
if (plane == 0)
fmt->fmt.vbi.samples_per_line = bytesperline;
break;
}
}
static inline __u32
v4l_format_g_bytesperline(const struct v4l2_format *fmt, unsigned plane)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return plane ? 0 : fmt->fmt.pix.bytesperline;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.plane_fmt[plane].bytesperline;
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
/* This assumes V4L2_PIX_FMT_GREY which is always the case */
return plane ? 0 : fmt->fmt.vbi.samples_per_line;
default:
return 0;
}
}
static inline void v4l_format_s_sizeimage(struct v4l2_format *fmt,
unsigned plane, __u32 sizeimage)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
if (plane == 0)
fmt->fmt.pix.sizeimage = sizeimage;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
fmt->fmt.pix_mp.plane_fmt[plane].sizeimage = sizeimage;
break;
}
}
static inline __u32
v4l_format_g_sizeimage(const struct v4l2_format *fmt, unsigned plane)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return plane ? 0 : fmt->fmt.pix.sizeimage;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return fmt->fmt.pix_mp.plane_fmt[plane].sizeimage;
case V4L2_BUF_TYPE_VBI_CAPTURE:
case V4L2_BUF_TYPE_VBI_OUTPUT:
/* This assumes V4L2_PIX_FMT_GREY which is always the case */
return plane ? 0 : fmt->fmt.vbi.samples_per_line *
(fmt->fmt.vbi.count[0] + fmt->fmt.vbi.count[1]);
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
return plane ? 0 : fmt->fmt.sliced.io_size;
case V4L2_BUF_TYPE_SDR_CAPTURE:
case V4L2_BUF_TYPE_SDR_OUTPUT:
return plane ? 0 : fmt->fmt.sdr.buffersize;
case V4L2_BUF_TYPE_META_CAPTURE:
case V4L2_BUF_TYPE_META_OUTPUT:
return plane ? 0 : fmt->fmt.meta.buffersize;
default:
return 0;
}
}
static inline int v4l_g_fmt(struct v4l_fd *f, struct v4l2_format *fmt, unsigned type)
{
v4l_format_init(fmt, type ? type : f->type);
return v4l_ioctl(f, VIDIOC_G_FMT, fmt);
}
static inline int v4l_try_fmt(struct v4l_fd *f, struct v4l2_format *fmt, bool zero_bpl)
{
/*
* Some drivers allow applications to set bytesperline to a larger value.
* In most cases you just want the driver to fill in the bytesperline field
* and so you have to zero bytesperline first.
*/
if (zero_bpl) {
__u8 p;
for (p = 0; p < v4l_format_g_num_planes(fmt); p++)
v4l_format_s_bytesperline(fmt, p, 0);
}
return v4l_ioctl(f, VIDIOC_TRY_FMT, fmt);
}
static inline int v4l_s_fmt(struct v4l_fd *f, struct v4l2_format *fmt, bool zero_bpl)
{
/*
* Some drivers allow applications to set bytesperline to a larger value.
* In most cases you just want the driver to fill in the bytesperline field
* and so you have to zero bytesperline first.
*/
if (zero_bpl) {
__u8 p;
for (p = 0; p < v4l_format_g_num_planes(fmt); p++)
v4l_format_s_bytesperline(fmt, p, 0);
}
return v4l_ioctl(f, VIDIOC_S_FMT, fmt);
}
struct v4l_buffer {
struct v4l2_plane planes[VIDEO_MAX_PLANES];
struct v4l2_buffer buf;
};
static inline void v4l_buffer_init(struct v4l_buffer *buf,
unsigned type, unsigned memory, unsigned index)
{
memset(buf, 0, sizeof(*buf));
buf->buf.type = type;
buf->buf.memory = memory;
buf->buf.index = index;
if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
buf->buf.m.planes = buf->planes;
buf->buf.length = VIDEO_MAX_PLANES;
}
}
static inline bool v4l_type_is_planar(unsigned type)
{
return V4L2_TYPE_IS_MULTIPLANAR(type);
}
static inline bool v4l_type_is_output(unsigned type)
{
return V4L2_TYPE_IS_OUTPUT(type);
}
static inline bool v4l_type_is_capture(unsigned type)
{
return V4L2_TYPE_IS_CAPTURE(type);
}
static inline bool v4l_type_is_video(unsigned type)
{
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return true;
default:
return false;
}
}
static inline bool v4l_type_is_raw_vbi(unsigned type)
{
return type == V4L2_BUF_TYPE_VBI_CAPTURE ||
type == V4L2_BUF_TYPE_VBI_OUTPUT;
}
static inline bool v4l_type_is_sliced_vbi(unsigned type)
{
return type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ||
type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
}
static inline bool v4l_type_is_vbi(unsigned type)
{
return v4l_type_is_raw_vbi(type) || v4l_type_is_sliced_vbi(type);
}
static inline bool v4l_type_is_overlay(unsigned type)
{
return type == V4L2_BUF_TYPE_VIDEO_OVERLAY ||
type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY;
}
static inline bool v4l_type_is_sdr(unsigned type)
{
return type == V4L2_BUF_TYPE_SDR_CAPTURE ||
type == V4L2_BUF_TYPE_SDR_OUTPUT;
}
static inline bool v4l_type_is_meta(unsigned type)
{
return type == V4L2_BUF_TYPE_META_CAPTURE ||
type == V4L2_BUF_TYPE_META_OUTPUT;
}
static inline unsigned v4l_type_invert(unsigned type)
{
if (v4l_type_is_planar(type))
return v4l_type_is_output(type) ?
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
return v4l_type_is_output(type) ?
V4L2_BUF_TYPE_VIDEO_CAPTURE :
V4L2_BUF_TYPE_VIDEO_OUTPUT;
}
static inline unsigned v4l_buffer_g_num_planes(const struct v4l_buffer *buf)
{
if (v4l_type_is_planar(buf->buf.type))
return buf->buf.length;
return 1;
}
static inline __u32 v4l_buffer_g_index(const struct v4l_buffer *buf)
{
return buf->buf.index;
}
static inline void v4l_buffer_s_index(struct v4l_buffer *buf, __u32 index)
{
buf->buf.index = index;
}
static inline __s32 v4l_buffer_g_request_fd(const struct v4l_buffer *buf)
{
return buf->buf.request_fd;
}
static inline void v4l_buffer_s_request_fd(struct v4l_buffer *buf, __s32 request_fd)
{
buf->buf.request_fd = request_fd;
}
static inline unsigned v4l_buffer_g_type(const struct v4l_buffer *buf)
{
return buf->buf.type;
}
static inline unsigned v4l_buffer_g_memory(const struct v4l_buffer *buf)
{
return buf->buf.memory;
}
static inline __u32 v4l_buffer_g_flags(const struct v4l_buffer *buf)
{
return buf->buf.flags;
}
static inline void v4l_buffer_s_flags(struct v4l_buffer *buf, __u32 flags)
{
buf->buf.flags = flags;
}
static inline void v4l_buffer_or_flags(struct v4l_buffer *buf, __u32 flags)
{
buf->buf.flags |= flags;
}
static inline unsigned v4l_buffer_g_field(const struct v4l_buffer *buf)
{
return buf->buf.field;
}
static inline void v4l_buffer_s_field(struct v4l_buffer *buf, unsigned field)
{
buf->buf.field = field;
}
static inline __u32 v4l_buffer_g_sequence(const struct v4l_buffer *buf)
{
return buf->buf.sequence;
}
static inline const struct timeval *v4l_buffer_g_timestamp(const struct v4l_buffer *buf)
{
return &buf->buf.timestamp;
}
static inline void v4l_buffer_s_timestamp(struct v4l_buffer *buf, const struct timeval *tv)
{
buf->buf.timestamp = *tv;
}
static inline void v4l_buffer_s_timestamp_ts(struct v4l_buffer *buf, const struct timespec *ts)
{
buf->buf.timestamp.tv_sec = ts->tv_sec;
buf->buf.timestamp.tv_usec = ts->tv_nsec / 1000;
}
static inline void v4l_buffer_s_timestamp_clock(struct v4l_buffer *buf)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
v4l_buffer_s_timestamp_ts(buf, &ts);
}
static inline const struct v4l2_timecode *v4l_buffer_g_timecode(const struct v4l_buffer *buf)
{
return &buf->buf.timecode;
}
static inline void v4l_buffer_s_timecode(struct v4l_buffer *buf, const struct v4l2_timecode *tc)
{
buf->buf.timecode = *tc;
}
static inline __u32 v4l_buffer_g_timestamp_type(const struct v4l_buffer *buf)
{
return buf->buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MASK;
}
static inline bool v4l_buffer_is_copy(const struct v4l_buffer *buf)
{
return v4l_buffer_g_timestamp_type(buf) == V4L2_BUF_FLAG_TIMESTAMP_COPY;
}
static inline __u32 v4l_buffer_g_timestamp_src(const struct v4l_buffer *buf)
{
return buf->buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
}
static inline void v4l_buffer_s_timestamp_src(struct v4l_buffer *buf, __u32 src)
{
buf->buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
buf->buf.flags |= src & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
}
static inline unsigned v4l_buffer_g_length(const struct v4l_buffer *buf, unsigned plane)
{
if (v4l_type_is_planar(buf->buf.type))
return buf->planes[plane].length;
return plane ? 0 : buf->buf.length;
}
static inline void v4l_buffer_s_length(struct v4l_buffer *buf, unsigned plane, unsigned length)
{
if (v4l_type_is_planar(buf->buf.type))
buf->planes[plane].length = length;
else if (plane == 0)
buf->buf.length = length;
}
static inline unsigned v4l_buffer_g_bytesused(const struct v4l_buffer *buf, unsigned plane)
{
if (v4l_type_is_planar(buf->buf.type))
return buf->planes[plane].bytesused;
return plane ? 0 : buf->buf.bytesused;
}
static inline void v4l_buffer_s_bytesused(struct v4l_buffer *buf, unsigned plane, __u32 bytesused)
{
if (v4l_type_is_planar(buf->buf.type))
buf->planes[plane].bytesused = bytesused;
else if (plane == 0)
buf->buf.bytesused = bytesused;
}
static inline unsigned v4l_buffer_g_data_offset(const struct v4l_buffer *buf, unsigned plane)
{
if (v4l_type_is_planar(buf->buf.type))
return buf->planes[plane].data_offset;
return 0;
}
static inline void v4l_buffer_s_data_offset(struct v4l_buffer *buf, unsigned plane, __u32 data_offset)
{
if (v4l_type_is_planar(buf->buf.type))
buf->planes[plane].data_offset = data_offset;
}
static inline __u32 v4l_buffer_g_mem_offset(const struct v4l_buffer *buf, unsigned plane)
{
if (v4l_type_is_planar(buf->buf.type))
return buf->planes[plane].m.mem_offset;
return plane ? 0 : buf->buf.m.offset;
}
static inline void v4l_buffer_s_userptr(struct v4l_buffer *buf, unsigned plane, void *userptr)
{
if (v4l_type_is_planar(buf->buf.type))
buf->planes[plane].m.userptr = (unsigned long)userptr;
else if (plane == 0)
buf->buf.m.userptr = (unsigned long)userptr;
}
static inline void *v4l_buffer_g_userptr(const struct v4l_buffer *buf, unsigned plane)
{
if (v4l_type_is_planar(buf->buf.type))
return (void *)buf->planes[plane].m.userptr;
return plane ? NULL : (void *)buf->buf.m.userptr;
}
static inline void v4l_buffer_s_fd(struct v4l_buffer *buf, unsigned plane, int fd)
{
if (v4l_type_is_planar(buf->buf.type))
buf->planes[plane].m.fd = fd;
else if (plane == 0)
buf->buf.m.fd = fd;
}
static inline int v4l_buffer_g_fd(const struct v4l_buffer *buf, unsigned plane)
{
if (v4l_type_is_planar(buf->buf.type))
return buf->planes[plane].m.fd;
return plane ? -1 : buf->buf.m.fd;
}
static inline int v4l_buffer_prepare_buf(struct v4l_fd *f, struct v4l_buffer *buf)
{
return v4l_ioctl(f, VIDIOC_PREPARE_BUF, &buf->buf);
}
static inline int v4l_buffer_qbuf(struct v4l_fd *f, struct v4l_buffer *buf)
{
return v4l_ioctl(f, VIDIOC_QBUF, &buf->buf);
}
static inline int v4l_buffer_dqbuf(struct v4l_fd *f, struct v4l_buffer *buf)
{
return v4l_ioctl(f, VIDIOC_DQBUF, &buf->buf);
}
static inline int v4l_buffer_querybuf(struct v4l_fd *f, struct v4l_buffer *buf, unsigned index)
{
v4l_buffer_s_index(buf, index);
return v4l_ioctl(f, VIDIOC_QUERYBUF, &buf->buf);
}
struct v4l_queue {
unsigned type;
unsigned memory;
unsigned buffers;
unsigned mappings;
unsigned num_planes;
unsigned capabilities;
__u32 lengths[VIDEO_MAX_PLANES];
__u32 mem_offsets[VIDEO_MAX_FRAME][VIDEO_MAX_PLANES];
void *mmappings[VIDEO_MAX_FRAME][VIDEO_MAX_PLANES];
unsigned long userptrs[VIDEO_MAX_FRAME][VIDEO_MAX_PLANES];
int fds[VIDEO_MAX_FRAME][VIDEO_MAX_PLANES];
};
static inline void v4l_queue_init(struct v4l_queue *q,
unsigned type, unsigned memory)
{
unsigned i, p;
memset(q, 0, sizeof(*q));
q->type = type;
q->memory = memory;
for (i = 0; i < VIDEO_MAX_FRAME; i++)
for (p = 0; p < VIDEO_MAX_PLANES; p++)
q->fds[i][p] = -1;
}
static inline unsigned v4l_queue_g_type(const struct v4l_queue *q) { return q->type; }
static inline unsigned v4l_queue_g_memory(const struct v4l_queue *q) { return q->memory; }
static inline unsigned v4l_queue_g_buffers(const struct v4l_queue *q) { return q->buffers; }
static inline unsigned v4l_queue_g_mappings(const struct v4l_queue *q) { return q->mappings; }
static inline unsigned v4l_queue_g_num_planes(const struct v4l_queue *q) { return q->num_planes; }
static inline unsigned v4l_queue_g_capabilities(const struct v4l_queue *q) { return q->capabilities; }
static inline __u32 v4l_queue_g_length(const struct v4l_queue *q, unsigned plane)
{
return q->lengths[plane];
}
static inline __u32 v4l_queue_g_mem_offset(const struct v4l_queue *q, unsigned index, unsigned plane)
{
return q->mem_offsets[index][plane];
}
static inline void v4l_queue_s_mmapping(struct v4l_queue *q, unsigned index, unsigned plane, void *m)
{
q->mmappings[index][plane] = m;
}
static inline void *v4l_queue_g_mmapping(const struct v4l_queue *q, unsigned index, unsigned plane)
{
if (index >= v4l_queue_g_mappings(q) || plane >= v4l_queue_g_num_planes(q))
return NULL;
return q->mmappings[index][plane];
}
static inline void v4l_queue_s_userptr(struct v4l_queue *q, unsigned index, unsigned plane, void *m)
{
q->userptrs[index][plane] = (unsigned long)m;
}
static inline void *v4l_queue_g_userptr(const struct v4l_queue *q, unsigned index, unsigned plane)
{
if (index >= v4l_queue_g_buffers(q) || plane >= v4l_queue_g_num_planes(q))
return NULL;
return (void *)q->userptrs[index][plane];
}
static inline void v4l_queue_s_fd(struct v4l_queue *q, unsigned index, unsigned plane, int fd)
{
q->fds[index][plane] = fd;
}
static inline int v4l_queue_g_fd(const struct v4l_queue *q, unsigned index, unsigned plane)
{
return q->fds[index][plane];
}
static inline void *v4l_queue_g_dataptr(const struct v4l_queue *q, unsigned index, unsigned plane)
{
if (q->memory == V4L2_MEMORY_USERPTR)
return v4l_queue_g_userptr(q, index, plane);
return v4l_queue_g_mmapping(q, index, plane);
}
static inline int v4l_queue_querybufs(struct v4l_fd *f, struct v4l_queue *q, unsigned from)
{
unsigned b, p;
int ret;
for (b = from; b < v4l_queue_g_buffers(q); b++) {
struct v4l_buffer buf;
v4l_buffer_init(&buf, v4l_queue_g_type(q), v4l_queue_g_memory(q), b);
ret = v4l_ioctl(f, VIDIOC_QUERYBUF, &buf.buf);
if (ret)
return ret;
if (b == 0) {
q->num_planes = v4l_buffer_g_num_planes(&buf);
for (p = 0; p < v4l_queue_g_num_planes(q); p++)
q->lengths[p] = v4l_buffer_g_length(&buf, p);
}
if (q->memory == V4L2_MEMORY_MMAP)
for (p = 0; p < q->num_planes; p++)
q->mem_offsets[b][p] = v4l_buffer_g_mem_offset(&buf, p);
}
return 0;
}
static inline int v4l_queue_reqbufs(struct v4l_fd *f,
struct v4l_queue *q, unsigned count, unsigned int flags = 0)
{
struct v4l2_requestbuffers reqbufs;
int ret;
reqbufs.type = q->type;
reqbufs.memory = q->memory;
reqbufs.count = count;
reqbufs.flags = flags;
/*
* Problem: if REQBUFS returns an error, did it free any old
* buffers or not?
*/
ret = v4l_ioctl(f, VIDIOC_REQBUFS, &reqbufs);
if (ret)
return ret;
q->buffers = reqbufs.count;
q->capabilities = reqbufs.capabilities;
return v4l_queue_querybufs(f, q, 0);
}
static inline bool v4l_queue_has_create_bufs(struct v4l_fd *f, const struct v4l_queue *q)
{
struct v4l2_create_buffers createbufs;
memset(&createbufs, 0, sizeof(createbufs));
createbufs.format.type = q->type;
createbufs.memory = q->memory;
return v4l_ioctl(f, VIDIOC_CREATE_BUFS, &createbufs) == 0;
}
static inline int v4l_queue_create_bufs(struct v4l_fd *f,
struct v4l_queue *q, unsigned count,
const struct v4l2_format *fmt, unsigned int flags = 0)
{
struct v4l2_create_buffers createbufs;
int ret;
createbufs.format.type = q->type;
createbufs.memory = q->memory;
createbufs.count = count;
createbufs.flags = flags;
if (fmt) {
createbufs.format = *fmt;
} else {
ret = v4l_g_fmt(f, &createbufs.format, q->type);
if (ret)
return ret;
}
memset(createbufs.reserved, 0, sizeof(createbufs.reserved));
ret = v4l_ioctl(f, VIDIOC_CREATE_BUFS, &createbufs);
if (ret)
return ret;
q->capabilities = createbufs.capabilities;
q->buffers += createbufs.count;
return v4l_queue_querybufs(f, q, q->buffers - createbufs.count);
}
static inline int v4l_queue_mmap_bufs(struct v4l_fd *f,
struct v4l_queue *q, unsigned from)
{
unsigned b, p;
if (q->memory != V4L2_MEMORY_MMAP && q->memory != V4L2_MEMORY_DMABUF)
return 0;
for (b = from; b < v4l_queue_g_buffers(q); b++) {
for (p = 0; p < v4l_queue_g_num_planes(q); p++) {
void *m = MAP_FAILED;
if (q->memory == V4L2_MEMORY_MMAP)
m = v4l_mmap(f, v4l_queue_g_length(q, p), v4l_queue_g_mem_offset(q, b, p));
else if (q->memory == V4L2_MEMORY_DMABUF)
m = mmap(NULL, v4l_queue_g_length(q, p),
PROT_READ | PROT_WRITE, MAP_SHARED,
v4l_queue_g_fd(q, b, p), 0);
if (m == MAP_FAILED)
return errno;
v4l_queue_s_mmapping(q, b, p, m);
}
}
q->mappings = b;
return 0;
}
static inline int v4l_queue_munmap_bufs(struct v4l_fd *f, struct v4l_queue *q,
unsigned from)
{
unsigned b, p;
int ret = 0;
if (q->memory != V4L2_MEMORY_MMAP && q->memory != V4L2_MEMORY_DMABUF)
return 0;
for (b = from; b < v4l_queue_g_mappings(q); b++) {
for (p = 0; p < v4l_queue_g_num_planes(q); p++) {
void *m = v4l_queue_g_mmapping(q, b, p);
if (m == NULL)
continue;
if (q->memory == V4L2_MEMORY_MMAP)
ret = v4l_munmap(f, m, v4l_queue_g_length(q, p));
else if (q->memory == V4L2_MEMORY_DMABUF)
ret = munmap(m, v4l_queue_g_length(q, p)) ? errno : 0;
if (ret)
return ret;
v4l_queue_s_mmapping(q, b, p, NULL);
}
}
q->mappings = from;
return 0;
}
static inline int v4l_queue_alloc_bufs(struct v4l_fd *f,
struct v4l_queue *q, unsigned from)
{
unsigned b, p;
if (q->memory != V4L2_MEMORY_USERPTR)
return 0;
for (b = from; b < v4l_queue_g_buffers(q); b++) {
for (p = 0; p < v4l_queue_g_num_planes(q); p++) {
void *m = malloc(v4l_queue_g_length(q, p));
if (m == NULL)
return errno;
v4l_queue_s_userptr(q, b, p, m);
}
}
return 0;
}
static inline int v4l_queue_free_bufs(struct v4l_queue *q, unsigned from)
{
unsigned b, p;
if (q->memory != V4L2_MEMORY_USERPTR)
return 0;
for (b = from; b < v4l_queue_g_buffers(q); b++) {
for (p = 0; p < v4l_queue_g_num_planes(q); p++) {
free(v4l_queue_g_userptr(q, b, p));
v4l_queue_s_userptr(q, b, p, NULL);
}
}
return 0;
}
static inline int v4l_queue_obtain_bufs(struct v4l_fd *f,
struct v4l_queue *q, unsigned from)
{
if (q->memory == V4L2_MEMORY_USERPTR)
return v4l_queue_alloc_bufs(f, q, from);
return v4l_queue_mmap_bufs(f, q, from);
}
static inline int v4l_queue_release_bufs(struct v4l_fd *f, struct v4l_queue *q,
unsigned from)
{
if (q->memory == V4L2_MEMORY_USERPTR)
return v4l_queue_free_bufs(q, from);
return v4l_queue_munmap_bufs(f, q, from);
}
static inline bool v4l_queue_has_expbuf(struct v4l_fd *f)
{
struct v4l2_exportbuffer expbuf;
memset(&expbuf, 0, sizeof(expbuf));
return v4l_ioctl(f, VIDIOC_EXPBUF, &expbuf) != ENOTTY;
}
static inline int v4l_queue_export_bufs(struct v4l_fd *f, struct v4l_queue *q,
unsigned exp_type)
{
struct v4l2_exportbuffer expbuf;
unsigned b, p;
int ret = 0;
expbuf.type = exp_type ? : f->type;
expbuf.flags = O_RDWR;
memset(expbuf.reserved, 0, sizeof(expbuf.reserved));
for (b = 0; b < v4l_queue_g_buffers(q); b++) {
expbuf.index = b;
for (p = 0; p < v4l_queue_g_num_planes(q); p++) {
expbuf.plane = p;
ret = v4l_ioctl(f, VIDIOC_EXPBUF, &expbuf);
if (ret)
return ret;
v4l_queue_s_fd(q, b, p, expbuf.fd);
}
}
return 0;
}
static inline void v4l_queue_close_exported_fds(struct v4l_queue *q)
{
unsigned b, p;
if (q->memory != V4L2_MEMORY_MMAP)
return;
for (b = 0; b < v4l_queue_g_buffers(q); b++) {
for (p = 0; p < v4l_queue_g_num_planes(q); p++) {
int fd = v4l_queue_g_fd(q, b, p);
if (fd != -1) {
close(fd);
v4l_queue_s_fd(q, b, p, -1);
}
}
}
}
static inline void v4l_queue_free(struct v4l_fd *f, struct v4l_queue *q)
{
v4l_ioctl(f, VIDIOC_STREAMOFF, &q->type);
v4l_queue_release_bufs(f, q, 0);
v4l_queue_close_exported_fds(q);
v4l_queue_reqbufs(f, q, 0, 0);
}
static inline void v4l_queue_buffer_update(const struct v4l_queue *q,
struct v4l_buffer *buf, unsigned index)
{
unsigned p;
if (v4l_type_is_planar(q->type)) {
buf->buf.length = v4l_queue_g_num_planes(q);
buf->buf.m.planes = buf->planes;
}
switch (q->memory) {
case V4L2_MEMORY_USERPTR:
for (p = 0; p < v4l_queue_g_num_planes(q); p++) {
v4l_buffer_s_userptr(buf, p, v4l_queue_g_userptr(q, index, p));
v4l_buffer_s_length(buf, p, v4l_queue_g_length(q, p));
}
break;
case V4L2_MEMORY_DMABUF:
for (p = 0; p < v4l_queue_g_num_planes(q); p++)
v4l_buffer_s_fd(buf, p, v4l_queue_g_fd(q, index, p));
break;
default:
break;
}
}
static inline void v4l_queue_buffer_init(const struct v4l_queue *q, struct v4l_buffer *buf, unsigned index)
{
v4l_buffer_init(buf, v4l_queue_g_type(q), v4l_queue_g_memory(q), index);
v4l_queue_buffer_update(q, buf, index);
}
static inline int v4l_query_ext_ctrl(v4l_fd *f, struct v4l2_query_ext_ctrl *qec,
bool next_ctrl, bool next_compound)
{
struct v4l2_queryctrl qc;
int ret;
if (next_compound && !f->have_query_ext_ctrl) {
if (!next_ctrl)
return -EINVAL;
next_compound = false;
}
if (next_compound)
qec->id |= V4L2_CTRL_FLAG_NEXT_COMPOUND;
if (next_ctrl) {
if (f->have_next_ctrl)
qec->id |= V4L2_CTRL_FLAG_NEXT_CTRL;
else
qec->id = qec->id ? qec->id + 1 : V4L2_CID_BASE;
}
if (f->have_query_ext_ctrl)
return v4l_ioctl(f, VIDIOC_QUERY_EXT_CTRL, qec);
for (;;) {
if (qec->id == V4L2_CID_LASTP1 && next_ctrl)
qec->id = V4L2_CID_PRIVATE_BASE;
qc.id = qec->id;
ret = v4l_ioctl(f, VIDIOC_QUERYCTRL, &qc);
if (!ret)
break;
if (ret != EINVAL)
return ret;
if (!next_ctrl || f->have_next_ctrl)
return ret;
if (qec->id >= V4L2_CID_PRIVATE_BASE)
return ret;
qec->id++;
}
qec->id = qc.id;
qec->type = qc.type;
memcpy(qec->name, qc.name, sizeof(qec->name));
qec->minimum = qc.minimum;
if (qc.type == V4L2_CTRL_TYPE_BITMASK) {
qec->maximum = (__u32)qc.maximum;
qec->default_value = (__u32)qc.default_value;
} else {
qec->maximum = qc.maximum;
qec->default_value = qc.default_value;
}
qec->step = qc.step;
qec->flags = qc.flags;
qec->elems = 1;
qec->nr_of_dims = 0;
memset(qec->dims, 0, sizeof(qec->dims));
switch (qec->type) {
case V4L2_CTRL_TYPE_INTEGER64:
qec->elem_size = sizeof(__s64);
qec->minimum = 0x8000000000000000ULL;
qec->maximum = 0x7fffffffffffffffULL;
qec->step = 1;
break;
case V4L2_CTRL_TYPE_STRING:
qec->elem_size = qc.maximum + 1;
qec->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
break;
default:
qec->elem_size = sizeof(__s32);
break;
}
memset(qec->reserved, 0, sizeof(qec->reserved));
return 0;
}
static inline int v4l_g_ext_ctrls(v4l_fd *f, struct v4l2_ext_controls *ec)
{
unsigned i;
if (f->have_ext_ctrls)
return v4l_ioctl(f, VIDIOC_G_EXT_CTRLS, ec);
if (ec->count == 0)
return 0;
for (i = 0; i < ec->count; i++) {
struct v4l2_control c = { ec->controls[i].id, 0 };
int ret = v4l_ioctl(f, VIDIOC_G_CTRL, &c);
if (ret) {
ec->error_idx = i;
return ret;
}
ec->controls[i].value = c.value;
}
return 0;
}
static inline int v4l_s_ext_ctrls(v4l_fd *f, struct v4l2_ext_controls *ec)
{
unsigned i;
if (f->have_ext_ctrls)
return v4l_ioctl(f, VIDIOC_S_EXT_CTRLS, ec);
if (ec->count == 0)
return 0;
for (i = 0; i < ec->count; i++) {
struct v4l2_control c = { ec->controls[i].id, ec->controls[i].value };
int ret = v4l_ioctl(f, VIDIOC_S_CTRL, &c);
if (ret) {
ec->error_idx = i;
return ret;
}
}
return 0;
}
static inline int v4l_try_ext_ctrls(v4l_fd *f, struct v4l2_ext_controls *ec)
{
unsigned i;
if (f->have_ext_ctrls)
return v4l_ioctl(f, VIDIOC_TRY_EXT_CTRLS, ec);
if (ec->count == 0)
return 0;
for (i = 0; i < ec->count; i++) {
struct v4l2_queryctrl qc;
int ret;
memset(&qc, 0, sizeof(qc));
qc.id = ec->controls[i].id;
ret = v4l_ioctl(f, VIDIOC_QUERYCTRL, &qc);
if (ret || qc.type == V4L2_CTRL_TYPE_STRING ||
qc.type == V4L2_CTRL_TYPE_INTEGER64) {
ec->error_idx = i;
return ret ? ret : EINVAL;
}
}
return 0;
}
static inline int v4l_g_selection(v4l_fd *f, struct v4l2_selection *sel)
{
struct v4l2_cropcap cc;
struct v4l2_crop crop;
int ret;
if (f->have_selection)
return v4l_ioctl(f, VIDIOC_G_SELECTION, sel);
crop.type = sel->type;
cc.type = sel->type;
ret = v4l_ioctl(f, VIDIOC_CROPCAP, &cc);
if (ret)
return ret;
ret = v4l_ioctl(f, VIDIOC_G_CROP, &crop);
if (ret)
return ret;
if (sel->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
sel->r = crop.c;
return 0;
case V4L2_SEL_TGT_CROP_DEFAULT:
sel->r = cc.defrect;
return 0;
case V4L2_SEL_TGT_CROP_BOUNDS:
sel->r = cc.bounds;
return 0;
default:
return EINVAL;
}
}
switch (sel->target) {
case V4L2_SEL_TGT_COMPOSE:
sel->r = crop.c;
return 0;
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
sel->r = cc.defrect;
return 0;
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
sel->r = cc.bounds;
return 0;
default:
return EINVAL;
}
}
static inline int v4l_s_selection(v4l_fd *f, struct v4l2_selection *sel)
{
struct v4l2_crop crop;
int ret;
if (f->have_selection)
return v4l_ioctl(f, VIDIOC_S_SELECTION, sel);
crop.type = sel->type;
ret = v4l_ioctl(f, VIDIOC_G_CROP, &crop);
if (ret)
return ret;
if (sel->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
sel->target == V4L2_SEL_TGT_CROP) {
crop.c = sel->r;
return v4l_ioctl(f, VIDIOC_S_CROP, &crop);
}
if (sel->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
sel->target == V4L2_SEL_TGT_COMPOSE) {
crop.c = sel->r;
return v4l_ioctl(f, VIDIOC_S_CROP, &crop);
}
return EINVAL;
}
static inline void v4l_frame_selection(struct v4l2_selection *sel, bool to_frame)
{
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
if (V4L2_TYPE_IS_CAPTURE(sel->type))
return;
break;
case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
case V4L2_SEL_TGT_COMPOSE_PADDED:
if (V4L2_TYPE_IS_OUTPUT(sel->type))
return;
break;
default:
return;
}
if (to_frame) {
sel->r.top *= 2;
sel->r.height *= 2;
} else {
sel->r.top /= 2;
sel->r.height /= 2;
}
}
static inline int v4l_g_frame_selection(v4l_fd *f, struct v4l2_selection *sel, __u32 field)
{
int ret = v4l_g_selection(f, sel);
if (V4L2_FIELD_HAS_T_OR_B(field))
v4l_frame_selection(sel, true);
return ret;
}
static inline int v4l_s_frame_selection(v4l_fd *f, struct v4l2_selection *sel, __u32 field)
{
int ret;
if (V4L2_FIELD_HAS_T_OR_B(field))
v4l_frame_selection(sel, false);
ret = v4l_s_selection(f, sel);
if (V4L2_FIELD_HAS_T_OR_B(field))
v4l_frame_selection(sel, true);
return ret;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif