44#ifdef HAVE_LIBV4LCONVERT
45#include <libv4lconvert.h>
47#ifdef HAVE_LINUX_VERSION_H
48#include <linux/version.h>
50#define KERNEL_VERSION(x,y,z) -1
69#define MOD_NAME "[V4L cap.] "
93#ifdef HAVE_LIBV4LCONVERT
94 struct v4lconvert_data *
convert;
119 if (ioctl(
s->
fd, VIDIOC_QBUF, &dequeue_data->
buf) != 0) {
131 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
132 if (
s->
fd != -1 && ioctl(
s->
fd, VIDIOC_STREAMOFF, &
type) != 0) {
136 pthread_mutex_lock(&
s->
lock);
139 pthread_cond_wait(&
s->
cv, &
s->
lock);
142 pthread_mutex_unlock(&
s->
lock);
152 pthread_cond_destroy(&
s->
cv);
153 pthread_mutex_destroy(&
s->
lock);
159#ifdef HAVE_LIBV4LCONVERT
161 v4lconvert_destroy(
s->convert);
169 int res = ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS,
param);
176 switch (
param->type) {
177 case V4L2_FRMIVAL_TYPE_DISCRETE:
178 while(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS,
param) == 0) {
179 printf(
"%u/%u ",
param->discrete.numerator,
180 param->discrete.denominator);
184 case V4L2_FRMIVAL_TYPE_CONTINUOUS:
187 case V4L2_FRMIVAL_TYPE_STEPWISE:
188 printf(
"%u/%u - %u/%u with step %u/%u",
189 param->stepwise.min.numerator,
190 param->stepwise.min.denominator,
191 param->stepwise.max.numerator,
192 param->stepwise.max.denominator,
193 param->stepwise.step.numerator,
194 param->stepwise.step.denominator);
202 for(
int i = 0; i < 4; i++){
203 out[i] = pixelformat & 0xff;
210 printf(
"V4L2 capture\n");
213 TRED(
"\t-t v4l2[:device=<dev>]")
214 "[:codec=<pixel_fmt>][:size=<width>x<height>][:tpf=<tpf>|:fps=<"
215 "fps>][:buffers=<bufcnt>][:convert=<conv>][:permissive]")
223 color_printf(
TERM_BOLD "\t<conv>" TERM_RESET " - SW conversion, eg. to RGB (useful eg. to convert captured MJPG from USB 2.0 webcam to uncompressed),\n"
224 "\t codecs available to convert to:");
225#ifdef HAVE_LIBV4LCONVERT
235 printf(
"\t\tpermissive - do not fail if configuration values (size, FPS) are adjusted by driver and not set exactly\n");
238 printf(
"Available devices:\n");
242 snprintf(
name, 32,
"/dev/video%d", i);
243 int fd = open(
name, O_RDWR);
245 if (errno != ENOENT) {
252 struct v4l2_capability capab;
253 memset(&capab, 0,
sizeof capab);
254 if (ioctl(fd, VIDIOC_QUERYCAP, &capab) != 0) {
259 if (!(capab.device_caps & V4L2_CAP_VIDEO_CAPTURE)){
265 struct v4l2_fmtdesc format;
266 memset(&format, 0,
sizeof(format));
267 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
270 struct v4l2_format
fmt;
271 memset(&
fmt, 0,
sizeof(
fmt));
272 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
273 if (ioctl(fd, VIDIOC_G_FMT, &
fmt) != 0) {
278 while (full && ioctl(fd, VIDIOC_ENUM_FMT, &format) == 0) {
280 if(
fmt.fmt.pix.pixelformat == format.pixelformat) {
285 printf(
"Pixel format ");
288 struct v4l2_frmsizeenum size;
289 memset(&size, 0,
sizeof(size));
290 size.pixel_format = format.pixelformat;
292 if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size) == -1) {
297 struct v4l2_frmivalenum frame_int;
298 memset(&frame_int, 0,
sizeof(frame_int));
300 frame_int.pixel_format = format.pixelformat;
303 case V4L2_FRMSIZE_TYPE_DISCRETE:
304 while(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size) == 0) {
306 if(
fmt.fmt.pix.width == size.discrete.width &&
307 fmt.fmt.pix.height == size.discrete.height) {
313 size.discrete.width, size.discrete.height);
314 frame_int.width = size.discrete.width;
315 frame_int.height = size.discrete.height;
322 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
323 printf(
"\t\t\t%u-%ux%u-%u with steps %u vertically and %u horizontally\n",
324 size.stepwise.min_width, size.stepwise.max_width,
325 size.stepwise.min_height, size.stepwise.max_height,
326 size.stepwise.step_width, size.stepwise.step_height);
328 case V4L2_FRMSIZE_TYPE_STEPWISE:
329 printf(
"\t\t\tany\n");
343 printf(
"(use \"shorthelp\" to display more terse output)\n");
347#ifdef HAVE_LIBV4LCONVERT
368 int width,
int height,
369 unsigned tpf_num,
unsigned tpf_denom,
372 double fps = (double) tpf_denom / tpf_num;
379 snprintf(m->name,
sizeof(m->name),
"%dx%d %.2f fps %4s",
380 width, height, fps,
codec);
382 snprintf(m->id,
sizeof(m->id),
"{"
383 "\"codec\":\"%.4s\", "
384 "\"size\":\"%dx%d\", "
385 "\"tpf\":\"%u/%u\", "
386 "\"force_rgb\":\"%c\"}",
389 tpf_num, tpf_denom, force_rgb ?
't' :
'f');
402 snprintf(
name, 32,
"/dev/video%d", i);
403 int fd = open(
name, O_RDWR);
404 if(fd == -1)
continue;
406 struct v4l2_capability capab;
407 memset(&capab, 0,
sizeof capab);
408 if (ioctl(fd, VIDIOC_QUERYCAP, &capab) != 0) {
412 if (!(capab.device_caps & V4L2_CAP_VIDEO_CAPTURE)){
417 cards = realloc(cards, card_count *
sizeof(
struct device_info));
418 memset(&cards[card_count - 1], 0,
sizeof(
struct device_info));
419 snprintf(cards[card_count - 1].dev,
sizeof cards[card_count - 1].dev,
":device=%s",
name);
420 snprintf(cards[card_count - 1].
name,
sizeof cards[card_count - 1].
name,
"V4L2 %s", capab.card);
422 struct v4l2_fmtdesc format;
423 memset(&format, 0,
sizeof(format));
424 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
428 while(ioctl(fd, VIDIOC_ENUM_FMT, &format) == 0) {
429 struct v4l2_frmsizeenum size;
430 memset(&size, 0,
sizeof(size));
431 size.pixel_format = format.pixelformat;
433 if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size) == -1) {
438 struct v4l2_frmivalenum frame_int;
439 memset(&frame_int, 0,
sizeof(frame_int));
441 frame_int.pixel_format = format.pixelformat;
444 case V4L2_FRMSIZE_TYPE_DISCRETE:
445 while(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size) == 0) {
446 frame_int.width = size.discrete.width;
447 frame_int.height = size.discrete.height;
450 if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_int) == -1) {
455 switch (frame_int.type) {
456 case V4L2_FRMIVAL_TYPE_DISCRETE:
457 while(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_int) == 0) {
458 write_mode(&cards[card_count - 1].modes[fmt_idx++],
459 size.discrete.width, size.discrete.height,
460 frame_int.discrete.numerator, frame_int.discrete.denominator,
480 *available_cards = cards;
484static _Bool
v4l2_cap_verify_params(_Bool permissive,
const struct v4l2_format *req_format,
const struct v4l2_format *actual_format,
struct v4l2_streamparm *req_stream_params,
struct v4l2_streamparm *actual_stream_params)
487 if (req_format->fmt.pix.pixelformat != actual_format->fmt.pix.pixelformat) {
488 log_msg(level,
MOD_NAME "Unable to set requested format \"%.4s\", got \"%.4s\".\n",
489 (
const char *) &req_format->fmt.pix.pixelformat, (
const char *) &actual_format->fmt.pix.pixelformat);
493 if (req_format->fmt.pix.width != actual_format->fmt.pix.width ||
494 req_format->fmt.pix.height != actual_format->fmt.pix.height) {
495 log_msg(level,
MOD_NAME "Unable to set requested size %" PRIu32
"x%" PRIu32
", got %" PRIu32
"x%" PRIu32
".\n",
496 req_format->fmt.pix.width, req_format->fmt.pix.height,
497 actual_format->fmt.pix.width, actual_format->fmt.pix.height);
501 if (req_stream_params->parm.capture.timeperframe.numerator != actual_stream_params->parm.capture.timeperframe.numerator ||
502 req_stream_params->parm.capture.timeperframe.denominator != actual_stream_params->parm.capture.timeperframe.denominator) {
503 log_msg(level,
MOD_NAME "Unable to set requested TPF %" PRIu32
"/%" PRIu32
", got %" PRIu32
"/%" PRIu32
".\n", req_stream_params->parm.capture.timeperframe.numerator, req_stream_params->parm.capture.timeperframe.denominator, actual_stream_params->parm.capture.timeperframe.numerator, actual_stream_params->parm.capture.timeperframe.denominator);
525 char *save_ptr = NULL;
527 while ((
item = strtok_r(
fmt,
":", &save_ptr))) {
533 char *
fmt = strchr(
item,
'=') + 1;
537 } str_to_uint = { .fourcc = 0 };
538 memcpy(str_to_uint.str,
fmt,
MIN(strlen(
fmt), 4));
541 strchr(
item,
'x') != NULL) {
542 opts->
width = atoi(strchr(
item,
'=') + 1);
548 : atoi(strchr(
item,
'/') + 1);
553 : atoi(strchr(
item,
'/') + 1);
558#ifdef HAVE_LIBV4LCONVERT
559 const char *
codec = strchr(
item,
'=') + 1;
568 MSG(ERROR,
"v4lconvert support not compiled in!");
574 MSG(ERROR,
"Invalid configuration argument: %s\n",
586 printf(
"vidcap_v4l2_init\n");
593 if (cfg && strstr(cfg,
"help") != NULL) {
594 show_help(strcmp(cfg,
"shorthelp") != 0);
600 printf(
"Unable to allocate v4l2 capture state\n");
605 pthread_mutex_init(&s->
lock, NULL);
606 pthread_cond_init(&s->
cv, NULL);
621 static_assert(
V4L2_PROBE_MAX < 100,
"Pattern below has place only for 2 digits");
622 char dev_name_try[] =
"/dev/videoXX";
627 snprintf(dev_name_try,
sizeof dev_name_try,
"/dev/video%d", i);
639 struct v4l2_format
fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
640 if (ioctl(s->
fd, VIDIOC_G_FMT, &
fmt) != 0) {
645 struct v4l2_streamparm stream_params = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
646 if (ioctl(s->
fd, VIDIOC_G_PARM, &stream_params) != 0) {
660 fmt.fmt.pix.field = V4L2_FIELD_ANY;
661 fmt.fmt.pix.bytesperline = 0;
663 struct v4l2_format req_fmt =
fmt;
664 if (ioctl(s->
fd, VIDIOC_S_FMT, &
fmt) != 0) {
669 stream_params.parm.capture.timeperframe.numerator =
671 stream_params.parm.capture.timeperframe.denominator =
674 struct v4l2_streamparm req_stream_params = stream_params;
676 ioctl(s->
fd, VIDIOC_S_PARM, &stream_params) != 0) {
678 MOD_NAME "Unable to set stream params");
685 assert(
fmt.type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
688 s->
dst_fmt.fmt.pix.bytesperline = 0;
689#if LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0)
690 s->
dst_fmt.fmt.pix.colorspace = V4L2_COLORSPACE_DEFAULT;
692 s->
dst_fmt.fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
695 if(ioctl(s->
fd, VIDIOC_G_PARM, &stream_params) != 0) {
706 memcpy(fcc, &
fmt.fmt.pix.pixelformat, 4);
713#ifdef HAVE_LIBV4LCONVERT
714 s->
dst_fmt.fmt.pix.pixelformat =
716 if (!v4lconvert_supported_dst_format(s->
dst_fmt.fmt.pix.pixelformat)) {
718 "Conversion to %s doesn't seem to be supported by "
719 "v4lconvert but proceeding as requested...\n",
723 if (s->
dst_fmt.fmt.pix.pixelformat == 0) {
724 MSG(ERROR,
"Cannot find %s to V4L2 mapping!\n",
743 s->
desc.
fps = (double) stream_params.parm.capture.timeperframe.denominator /
744 stream_params.parm.capture.timeperframe.numerator;
748#ifdef HAVE_LIBV4LCONVERT
751 s->convert = v4lconvert_create(s->
fd);
755 struct v4l2_requestbuffers reqbuf;
757 memset(&reqbuf, 0,
sizeof(reqbuf));
758 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
759 reqbuf.memory = V4L2_MEMORY_MMAP;
767 if(ioctl(s->
fd, VIDIOC_STREAMON, &reqbuf.type) != 0) {
772 gettimeofday(&s->
t0, NULL);
777 MSG(NOTICE,
"Capturing %dx%d @%.2f%s %s from %s\n", s->
desc.
width,
805 pthread_mutex_lock(&data->
s->
lock);
807 pthread_mutex_unlock(&data->
s->
lock);
808 pthread_cond_signal(&data->
s->
cv);
821 pthread_mutex_lock(&s->
lock);
824 pthread_cond_wait(&s->
cv, &s->
lock);
827 pthread_mutex_unlock(&s->
lock);
831 struct v4l2_buffer buf;
832 memset(&buf, 0,
sizeof(buf));
833 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
834 buf.memory = V4L2_MEMORY_MMAP;
836 if(ioctl(s->
fd, VIDIOC_DQBUF, &buf) != 0) {
846#ifdef HAVE_LIBV4LCONVERT
850 int ret = v4lconvert_convert(s->convert,
859 if (ioctl(s->
fd, VIDIOC_QBUF, &buf) != 0) {
879 memcpy(&frame_data->
buf, &
buf,
sizeof(
buf));
888 gettimeofday(&t, NULL);
891 float fps = s->
frames / seconds;
struct video_frame * frame
struct audio_frame ** audio
int void(** deleter)(void *))
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
const char * get_codec_name(codec_t codec)
codec_t get_codec_from_name(const char *name)
int color_printf(const char *format,...)
void log_msg(int level, const char *format,...)
void log_perror(int level, const char *msg)
#define LOG_LEVEL_INFO
normal reporting
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_VERBOSE
#define LOG_LEVEL_WARNING
less severe errors
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDCAP_NO_GENERIC_FPS_INDICATOR
#define VIDEO_CAPTURE_ABI_VERSION
#define VIDCAP_INIT_FAIL
error ocured
#define VIDCAP_INIT_AUDIO_NOT_SUPPORTED
card does not support audio
@ LIBRARY_CLASS_VIDEO_CAPTURE
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
void simple_linked_list_append(struct simple_linked_list *l, void *data)
struct simple_linked_list * simple_linked_list_init(void)
void simple_linked_list_destroy(struct simple_linked_list *l)
void * simple_linked_list_pop(struct simple_linked_list *l)
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
#define IS_PREFIX(tok, key)
similar as above, but also key without a value is accepted (value optional)
const char * ug_strerror(int errnum)
struct used to comunicate with audio capture/playback device
char * data
Raw tile data. Pointer must be at least 4B aligned.
unsigned int data_len
length of the data
struct vidcap_v4l2_state * s
struct v4l2_buffer_data buffers[MAX_BUF_COUNT]
_Bool permissive
do not fail if parameters (size, FPS...) not set exactly
struct v4l2_format dst_fmt
converted format if v4lconvert is used
struct simple_linked_list * buffers_to_enqueue
struct v4l2_format src_fmt
captured format
enum interlacing_t interlacing
unsigned int width
width of every tile (!)
unsigned int height
height of every tile (!)
void(* dispose)(struct video_frame *)
Struct video_frame represents a video frame and contains video description.
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
struct video_frame_callbacks callbacks
double tv_diff(struct timeval curr_time, struct timeval prev_time)
@ RGB
RGB 8-bit (packed into 24-bit word)
@ VIDEO_CODEC_NONE
dummy color spec
static struct @67 v4l2_field_map[]
static struct @68 v4l2_ug_map[]
static int try_open_v4l2_device(int log_level, const char *dev_name, int cap)
static _Bool set_v4l2_buffers(int fd, struct v4l2_requestbuffers *reqbuf, struct v4l2_buffer_data *buffers)
This is an umbrella header for video functions.
static codec_t get_v4l2_to_ug(uint32_t fcc)
static const struct video_capture_info vidcap_v4l2_info
static void print_fps(int fd, struct v4l2_frmivalenum *param)
static void vidcap_v4l2_done(void *state)
static void enqueue_all_finished_frames(struct vidcap_v4l2_state *s)
static void vidcap_v4l2_common_cleanup(struct vidcap_v4l2_state *s)
static void vidcap_v4l2_dispose_video_frame(struct video_frame *frame)
static void write_fcc(char *out, int pixelformat)
static void vidcap_v4l2_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
static bool parse_fmt(char *fmt, struct parsed_opts *opts)
static void write_mode(struct mode *m, int width, int height, unsigned tpf_num, unsigned tpf_denom, int pixelformat)
static struct video_frame * vidcap_v4l2_grab(void *state, struct audio_frame **audio)
static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
static _Bool v4l2_cap_verify_params(_Bool permissive, const struct v4l2_format *req_format, const struct v4l2_format *actual_format, struct v4l2_streamparm *req_stream_params, struct v4l2_streamparm *actual_stream_params)
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_ANY
bool is_codec_opaque(codec_t codec)
bool codec_is_planar(codec_t codec)
const char * get_interlacing_suffix(enum interlacing_t interlacing)
Returns suffix describing interlacing Eg. p, i or psf.
#define VIDEO_FRAME_DISPOSE(frame)