UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
v4l2.c
Go to the documentation of this file.
1
7 /*
8 * Copyright (c) 2012-2024 CESNET, z. s. p. o.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, is permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * 3. Neither the name of CESNET nor the names of its contributors may be
23 * used to endorse or promote products derived from this software without
24 * specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
28 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
29 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
30 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
31 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
36 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
37 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#ifdef HAVE_CONFIG_H
41#include "config.h"
42#endif /* HAVE_CONFIG_H */
43
44#ifdef HAVE_LIBV4LCONVERT
45#include <libv4lconvert.h>
46#endif
47#ifdef HAVE_LINUX_VERSION_H
48#include <linux/version.h>
49#else
50#define KERNEL_VERSION(x,y,z) -1
51#endif
52
53#include <assert.h>
54#include <errno.h>
55#include <fcntl.h>
56#include <inttypes.h>
57#include <pthread.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <sys/ioctl.h>
62#include <sys/mman.h>
63#include <unistd.h>
64
65enum {
68};
69#define MOD_NAME "[V4L cap.] "
70
71#include "debug.h"
72#include "host.h"
73#include "lib_common.h"
74#include "tv.h"
75#include "utils/color_out.h"
76#include "utils/list.h"
77#include "utils/macros.h"
78#include "utils/misc.h" // ug_strerror
79#include "v4l2_common.h"
80#include "video.h"
81#include "video_capture.h"
82
83/* prototypes of functions defined in this module */
84static void print_fps(int fd, struct v4l2_frmivalenum *param);
85
88
89 int fd;
91
92 _Bool permissive;
93#ifdef HAVE_LIBV4LCONVERT
94 struct v4lconvert_data *convert;
95#endif
96 struct v4l2_format src_fmt;
97 struct v4l2_format dst_fmt;
98
99 struct timeval t0;
101
103
106 pthread_mutex_t lock;
107 pthread_cond_t cv;
108};
109
112 struct v4l2_buffer buf;
113};
114
116 struct v4l2_dispose_deq_buffer_data *dequeue_data;
117 while ((dequeue_data = simple_linked_list_pop(s->buffers_to_enqueue)) != NULL) {
118 s->dequeued_buffers -= 1;
119 if (ioctl(s->fd, VIDIOC_QBUF, &dequeue_data->buf) != 0) {
120 log_perror(LOG_LEVEL_ERROR, "Unable to enqueue buffer");
121 }
122 free(dequeue_data);
123 }
124}
125
127 if (!s) {
128 return;
129 }
130
131 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
132 if (s->fd != -1 && ioctl(s->fd, VIDIOC_STREAMOFF, &type) != 0) {
133 log_perror(LOG_LEVEL_ERROR, MOD_NAME "Stream stopping error");
134 };
135
136 pthread_mutex_lock(&s->lock);
138 while (s->dequeued_buffers != 0) {
139 pthread_cond_wait(&s->cv, &s->lock);
141 }
142 pthread_mutex_unlock(&s->lock);
143
144 for (int i = 0; i < s->buffer_count; ++i) {
145 if (s->buffers[i].start) {
146 if (-1 == munmap(s->buffers[i].start, s->buffers[i].length)) {
148 }
149 }
150 }
151
152 pthread_cond_destroy(&s->cv);
153 pthread_mutex_destroy(&s->lock);
155
156 if (s->fd != -1)
157 close(s->fd);
158
159#ifdef HAVE_LIBV4LCONVERT
160 if (s->convert) {
161 v4lconvert_destroy(s->convert);
162 }
163#endif
164
165 free(s);
166}
167
168static void print_fps(int fd, struct v4l2_frmivalenum *param) {
169 int res = ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, param);
170
171 if(res == -1) {
172 log_perror(LOG_LEVEL_WARNING, MOD_NAME "Unable to get FPS");
173 return;
174 }
175
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);
181 param->index++;
182 }
183 break;
184 case V4L2_FRMIVAL_TYPE_CONTINUOUS:
185 printf("(any FPS)");
186 break;
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);
195 break;
196 }
197}
198
199static void write_fcc(char *out, int pixelformat){
200 out[4] = '\0';
201
202 for(int i = 0; i < 4; i++){
203 out[i] = pixelformat & 0xff;
204 pixelformat >>= 8;
205 }
206}
207
208static void show_help(_Bool full)
209{
210 printf("V4L2 capture\n");
211 printf("Usage\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]")
216 "\n");
217 color_printf("\t" TBOLD("-t v4l2:[short]help") "\n");
218 printf("where\n");
219 color_printf(TERM_BOLD "<dev> -" TERM_RESET "\tuse device to grab from (default: first usable)\n");
220 color_printf(TERM_BOLD "\t<tpf>" TERM_RESET " - time per frame in format <numerator>/<denominator>\n");
221 color_printf(TERM_BOLD "\t<bufcnt>" TERM_RESET " - number of capture buffers to be used (default: %d)\n", DEFAULT_BUF_COUNT);
222 color_printf(TERM_BOLD "\t<tpf>" TERM_RESET " or " TERM_BOLD "<fps>" TERM_RESET " should be given as a single integer or a fraction\n");
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
226 for (unsigned int i = 0; i < sizeof v4l2_ug_map / sizeof v4l2_ug_map[0]; ++i) {
227 if (v4lconvert_supported_dst_format(v4l2_ug_map[i].v4l2_fcc)) {
229 }
230 }
231#else
232 color_printf(TERM_FG_RED " v4lconvert support not compiled in!" TERM_RESET);
233#endif
234 printf("\n");
235 printf("\t\tpermissive - do not fail if configuration values (size, FPS) are adjusted by driver and not set exactly\n");
236 printf("\n");
237
238 printf("Available devices:\n");
239 for (int i = 0; i < V4L2_PROBE_MAX; ++i) {
240 char name[32];
241
242 snprintf(name, 32, "/dev/video%d", i);
243 int fd = open(name, O_RDWR);
244 if (fd == -1) {
245 if (errno != ENOENT) {
246 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Unable to open input device %s: %s\n",
247 name, ug_strerror(errno));
248 }
249 continue;
250 }
251
252 struct v4l2_capability capab;
253 memset(&capab, 0, sizeof capab);
254 if (ioctl(fd, VIDIOC_QUERYCAP, &capab) != 0) {
255 log_perror(LOG_LEVEL_WARNING, MOD_NAME "Unable to query device capabilities");
256 }
257
258 log_msg(LOG_LEVEL_VERBOSE, "Device %s capabilities: %#x (CAP_VIDEO_CAPTURE = %#x)\n", name, capab.device_caps, V4L2_CAP_VIDEO_CAPTURE);
259 if (!(capab.device_caps & V4L2_CAP_VIDEO_CAPTURE)){
260 goto next_device;
261 }
262
263 color_printf("\t%sDevice " TERM_BOLD "%s " TERM_RESET"%s (%s)%s\n", (i == 0 ? "(*) " : " "), name, capab.card, capab.bus_info, full ? ":" : "");
264
265 struct v4l2_fmtdesc format;
266 memset(&format, 0, sizeof(format));
267 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
268 format.index = 0;
269
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) {
274 log_perror(LOG_LEVEL_WARNING, MOD_NAME "Unable to get video format");
275 goto next_device;
276 }
277
278 while (full && ioctl(fd, VIDIOC_ENUM_FMT, &format) == 0) {
279 printf("\t\t");
280 if(fmt.fmt.pix.pixelformat == format.pixelformat) {
281 printf("(*) ");
282 } else {
283 printf(" ");
284 }
285 printf("Pixel format ");
286 color_printf(TERM_BOLD "%4.4s" TERM_RESET " (%s). Available frame sizes:\n", (const char *) &format.pixelformat, format.description);
287
288 struct v4l2_frmsizeenum size;
289 memset(&size, 0, sizeof(size));
290 size.pixel_format = format.pixelformat;
291
292 if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size) == -1) {
293 log_perror(LOG_LEVEL_ERROR, MOD_NAME "Unable to get frame size iterator");
294 goto next_device;
295 }
296
297 struct v4l2_frmivalenum frame_int;
298 memset(&frame_int, 0, sizeof(frame_int));
299 frame_int.index = 0;
300 frame_int.pixel_format = format.pixelformat;
301
302 switch (size.type) {
303 case V4L2_FRMSIZE_TYPE_DISCRETE:
304 while(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size) == 0) {
305 printf("\t\t\t");
306 if(fmt.fmt.pix.width == size.discrete.width &&
307 fmt.fmt.pix.height == size.discrete.height) {
308 printf("(*) ");
309 } else {
310 printf(" ");
311 }
312 printf("%ux%u\t",
313 size.discrete.width, size.discrete.height);
314 frame_int.width = size.discrete.width;
315 frame_int.height = size.discrete.height;
316 frame_int.index = 0;
317 print_fps(fd, &frame_int);
318 printf("\n");
319 size.index++;
320 }
321 break;
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);
327 break;
328 case V4L2_FRMSIZE_TYPE_STEPWISE:
329 printf("\t\t\tany\n");
330 break;
331 }
332
333 format.index++;
334 }
335
336 printf("\n");
337
338next_device:
339 close(fd);
340 }
341
342 if (full) {
343 printf("(use \"shorthelp\" to display more terse output)\n");
344 }
345}
346
347#ifdef HAVE_LIBV4LCONVERT
348static uint32_t get_ug_to_v4l2(codec_t ug_codec) {
349 for (unsigned int i = 0; i < sizeof v4l2_ug_map / sizeof v4l2_ug_map[0]; ++i) {
350 if (v4l2_ug_map[i].ug_codec == ug_codec) {
351 return v4l2_ug_map[i].v4l2_fcc;
352 }
353 }
354 return 0;
355}
356#endif
357
358static codec_t get_v4l2_to_ug(uint32_t fcc) {
359 for (unsigned int i = 0; i < sizeof v4l2_ug_map / sizeof v4l2_ug_map[0]; ++i) {
360 if (v4l2_ug_map[i].v4l2_fcc == fcc) {
361 return v4l2_ug_map[i].ug_codec;
362 }
363 }
364 return VIDEO_CODEC_NONE;
365}
366
367static void write_mode(struct mode *m,
368 int width, int height,
369 unsigned tpf_num, unsigned tpf_denom,
370 int pixelformat)
371{
372 double fps = (double) tpf_denom / tpf_num;
373 char codec[5];
374 write_fcc(codec, pixelformat);
375
376 codec_t ug_codec = get_v4l2_to_ug(pixelformat);
378
379 snprintf(m->name, sizeof(m->name), "%dx%d %.2f fps %4s",
380 width, height, fps, codec);
381
382 snprintf(m->id, sizeof(m->id), "{"
383 "\"codec\":\"%.4s\", "
384 "\"size\":\"%dx%d\", "
385 "\"tpf\":\"%u/%u\", "
386 "\"force_rgb\":\"%c\"}",
387 codec,
388 width, height,
389 tpf_num, tpf_denom, force_rgb ? 't' : 'f');
390}
391
392static void vidcap_v4l2_probe(struct device_info **available_cards, int *count, void (**deleter)(void *))
393{
394 *deleter = free;
395
396 int card_count = 0;
397 struct device_info *cards = NULL;
398
399 for (int i = 0; i < V4L2_PROBE_MAX; ++i) {
400 char name[32];
401
402 snprintf(name, 32, "/dev/video%d", i);
403 int fd = open(name, O_RDWR);
404 if(fd == -1) continue;
405
406 struct v4l2_capability capab;
407 memset(&capab, 0, sizeof capab);
408 if (ioctl(fd, VIDIOC_QUERYCAP, &capab) != 0) {
409 log_perror(LOG_LEVEL_WARNING, MOD_NAME "Unable to query device capabilities");
410 }
411
412 if (!(capab.device_caps & V4L2_CAP_VIDEO_CAPTURE)){
413 goto next_device;
414 }
415
416 card_count += 1;
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);
421
422 struct v4l2_fmtdesc format;
423 memset(&format, 0, sizeof(format));
424 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
425 format.index = 0;
426
427 int fmt_idx = 0;
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;
432
433 if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &size) == -1) {
434 log_perror(LOG_LEVEL_WARNING, MOD_NAME "Unable to get frame size iterator");
435 goto next_device;
436 }
437
438 struct v4l2_frmivalenum frame_int;
439 memset(&frame_int, 0, sizeof(frame_int));
440 frame_int.index = 0;
441 frame_int.pixel_format = format.pixelformat;
442
443 switch (size.type) {
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;
448 frame_int.index = 0;
449
450 if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_int) == -1) {
451 log_perror(LOG_LEVEL_WARNING, MOD_NAME "Unable to get FPS");
452 goto next_device;
453 }
454
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,
461 format.pixelformat);
462 frame_int.index++;
463 }
464 break;
465 default:
466 break;
467 }
468 size.index++;
469 }
470 break;
471 default:
472 break;
473 }
474
475 format.index++;
476 }
477next_device:
478 close(fd);
479 }
480 *available_cards = cards;
481 *count = card_count;
482}
483
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)
485{
486 int level = permissive ? LOG_LEVEL_WARNING : LOG_LEVEL_ERROR;
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);
490 return 0;
491 }
492
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);
498 return 0;
499 }
500
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);
504 return 0;
505 }
506
507 return 1;
508}
509
521
522static bool
523parse_fmt(char *fmt, struct parsed_opts *opts)
524{
525 char *save_ptr = NULL;
526 char *item = NULL;;
527 while ((item = strtok_r(fmt, ":", &save_ptr))) {
528 fmt = NULL;
529 if (IS_KEY_PREFIX(item, "device")) {
530 opts->dev_name = strchr(item, '=') + 1;
531 } else if (IS_KEY_PREFIX(item, "fmt") ||
532 IS_KEY_PREFIX(item, "codec")) {
533 char *fmt = strchr(item, '=') + 1;
534 union {
535 uint32_t fourcc;
536 char str[4];
537 } str_to_uint = { .fourcc = 0 };
538 memcpy(str_to_uint.str, fmt, MIN(strlen(fmt), 4));
539 opts->pixelformat = str_to_uint.fourcc;
540 } else if (IS_KEY_PREFIX(item, "size") &&
541 strchr(item, 'x') != NULL) {
542 opts->width = atoi(strchr(item, '=') + 1);
543 opts->height = atoi(strchr(item, 'x') + 1);
544 } else if (IS_KEY_PREFIX(item, "tpf")) {
545 opts->numerator = atoi(strchr(item, '=') + 1);
546 opts->denominator = strchr(item, '/') == NULL
547 ? 1
548 : atoi(strchr(item, '/') + 1);
549 } else if (IS_KEY_PREFIX(item, "fps")) {
550 opts->denominator = atoi(strchr(item, '=') + 1);
551 opts->numerator = strchr(item, '/') == NULL
552 ? 1
553 : atoi(strchr(item, '/') + 1);
554 } else if (IS_KEY_PREFIX(item, "buffers")) {
555 opts->buffer_count = atoi(strchr(item, '=') + 1);
556 assert(opts->buffer_count <= MAX_BUF_COUNT);
557 } else if (IS_KEY_PREFIX(item, "convert")) {
558#ifdef HAVE_LIBV4LCONVERT
559 const char *codec = strchr(item, '=') + 1;
561 if (opts->v4l2_convert_to == VIDEO_CODEC_NONE) {
563 MOD_NAME "Unknown codec: %s\n",
564 codec);
565 return false;
566 }
567#else
568 MSG(ERROR, "v4lconvert support not compiled in!");
569 return false;
570#endif
571 } else if (IS_PREFIX(item, "permissive")) {
572 opts->permissive = 1;
573 } else {
574 MSG(ERROR, "Invalid configuration argument: %s\n",
575 item);
576 return false;
577 }
578 }
579 return true;
580}
581
582static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
583{
584 struct parsed_opts opts = { .buffer_count = DEFAULT_BUF_COUNT };
585
586 printf("vidcap_v4l2_init\n");
587
590 }
591
592 const char *cfg = vidcap_params_get_fmt(params);
593 if (cfg && strstr(cfg, "help") != NULL) {
594 show_help(strcmp(cfg, "shorthelp") != 0);
595 return VIDCAP_INIT_NOERR;
596 }
597
598 struct vidcap_v4l2_state *s = calloc(1, sizeof(struct vidcap_v4l2_state));
599 if(s == NULL) {
600 printf("Unable to allocate v4l2 capture state\n");
601 return VIDCAP_INIT_FAIL;
602 }
603 s->fd = -1;
605 pthread_mutex_init(&s->lock, NULL);
606 pthread_cond_init(&s->cv, NULL);
607
608 char *tmp = NULL;
609
611 tmp = strdup(vidcap_params_get_fmt(params));
612 assert(tmp != NULL);
613 if (!parse_fmt(tmp, &opts)) {
614 goto error;
615 }
616 }
617
618 s->buffer_count = opts.buffer_count;
619 s->permissive= opts.permissive;
620
621 static_assert(V4L2_PROBE_MAX < 100, "Pattern below has place only for 2 digits");
622 char dev_name_try[] = "/dev/videoXX";
623 if (opts.dev_name != NULL) {
624 s->fd = try_open_v4l2_device(LOG_LEVEL_ERROR, opts.dev_name, V4L2_CAP_VIDEO_CAPTURE);
625 } else {
626 for (int i = 0; i < V4L2_PROBE_MAX; ++i) {
627 snprintf(dev_name_try, sizeof dev_name_try, "/dev/video%d", i);
628 s->fd = try_open_v4l2_device(LOG_LEVEL_WARNING, dev_name_try, V4L2_CAP_VIDEO_CAPTURE);
629 if (s->fd != -1) {
630 opts.dev_name = dev_name_try;
631 break;
632 }
633 }
634 }
635 if (s->fd == -1) {
636 goto error;
637 }
638
639 struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
640 if (ioctl(s->fd, VIDIOC_G_FMT, &fmt) != 0) {
641 log_perror(LOG_LEVEL_ERROR, MOD_NAME "Unable to get video format");
642 goto error;
643 }
644
645 struct v4l2_streamparm stream_params = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
646 if (ioctl(s->fd, VIDIOC_G_PARM, &stream_params) != 0) {
647 log_perror(LOG_LEVEL_ERROR, MOD_NAME "Unable to get stream params");
648 goto error;
649 }
650
651 if (opts.pixelformat) {
652 fmt.fmt.pix.pixelformat = opts.pixelformat;
653 }
654
655 if (opts.width != 0 && opts.height != 0) {
656 fmt.fmt.pix.width = opts.width;
657 fmt.fmt.pix.height = opts.height;
658 }
659
660 fmt.fmt.pix.field = V4L2_FIELD_ANY;
661 fmt.fmt.pix.bytesperline = 0;
662
663 struct v4l2_format req_fmt = fmt;
664 if (ioctl(s->fd, VIDIOC_S_FMT, &fmt) != 0) {
665 log_perror(LOG_LEVEL_ERROR, MOD_NAME "Unable to set video format");
666 goto error;
667 }
668 if (opts.numerator != 0 && opts.denominator != 0) {
669 stream_params.parm.capture.timeperframe.numerator =
670 opts.numerator;
671 stream_params.parm.capture.timeperframe.denominator =
672 opts.denominator;
673 }
674 struct v4l2_streamparm req_stream_params = stream_params;
675 if (opts.numerator != 0 && opts.denominator != 0 &&
676 ioctl(s->fd, VIDIOC_S_PARM, &stream_params) != 0) {
678 MOD_NAME "Unable to set stream params");
679 goto error;
680 }
681 if (!v4l2_cap_verify_params(s->permissive, &req_fmt, &fmt, &req_stream_params, &stream_params) && !s->permissive) {
682 goto error;
683 }
684
685 assert(fmt.type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
686 memcpy(&s->src_fmt, &fmt, sizeof(fmt));
687 memcpy(&s->dst_fmt, &fmt, sizeof(fmt));
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;
691#else // CentOS 7
692 s->dst_fmt.fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
693#endif
694
695 if(ioctl(s->fd, VIDIOC_G_PARM, &stream_params) != 0) {
696 log_perror(LOG_LEVEL_ERROR, MOD_NAME "Unable to get stream params");
697 goto error;
698 }
699
700 s->desc.tile_count = 1;
701
702 if (opts.v4l2_convert_to == VC_NONE) {
703 s->desc.color_spec = get_v4l2_to_ug(fmt.fmt.pix.pixelformat);
704 if (s->desc.color_spec == VIDEO_CODEC_NONE) {
705 char fcc[5];
706 memcpy(fcc, &fmt.fmt.pix.pixelformat, 4);
707 fcc[4] = '\0';
708 log_msg(LOG_LEVEL_WARNING, MOD_NAME "No mapping for FCC '%s', converting to RGB!\n", fcc);
709 opts.v4l2_convert_to = RGB;
710 }
711 }
712 if (opts.v4l2_convert_to != VC_NONE) {
713#ifdef HAVE_LIBV4LCONVERT
714 s->dst_fmt.fmt.pix.pixelformat =
715 get_ug_to_v4l2(opts.v4l2_convert_to);
716 if (!v4lconvert_supported_dst_format(s->dst_fmt.fmt.pix.pixelformat)) {
717 MSG(WARNING,
718 "Conversion to %s doesn't seem to be supported by "
719 "v4lconvert but proceeding as requested...\n",
721 }
722
723 if (s->dst_fmt.fmt.pix.pixelformat == 0) {
724 MSG(ERROR, "Cannot find %s to V4L2 mapping!\n",
726 goto error;
727 }
729#endif
730 }
731
732 unsigned i = 0;
733 for ( ; i < sizeof v4l2_field_map / sizeof v4l2_field_map[0]; ++i) {
734 if (v4l2_field_map[i].v4l_f == fmt.fmt.pix.field) {
735 s->desc.interlacing = v4l2_field_map[i].ug_f;
736 break;
737 }
738 }
739 if (i == sizeof v4l2_field_map / sizeof v4l2_field_map[0]) {
740 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unsupported interlacing format reported from driver (%d).\n", fmt.fmt.pix.field);
741 goto error;
742 }
743 s->desc.fps = (double) stream_params.parm.capture.timeperframe.denominator /
744 stream_params.parm.capture.timeperframe.numerator;
745 s->desc.width = fmt.fmt.pix.width;
746 s->desc.height = fmt.fmt.pix.height;
747
748#ifdef HAVE_LIBV4LCONVERT
749 s->convert = NULL;
750 if (opts.v4l2_convert_to != VC_NONE) {
751 s->convert = v4lconvert_create(s->fd);
752 }
753#endif
754
755 struct v4l2_requestbuffers reqbuf;
756
757 memset(&reqbuf, 0, sizeof(reqbuf));
758 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
759 reqbuf.memory = V4L2_MEMORY_MMAP;
760 reqbuf.count = s->buffer_count;
761
762 if (!set_v4l2_buffers(s->fd, &reqbuf, s->buffers)) {
763 goto error;
764 }
765 s->buffer_count = reqbuf.count;
766
767 if(ioctl(s->fd, VIDIOC_STREAMON, &reqbuf.type) != 0) {
768 log_perror(LOG_LEVEL_ERROR, MOD_NAME "Unable to start stream");
769 goto error;
770 };
771
772 gettimeofday(&s->t0, NULL);
773 s->frames = 0;
774
775 free(tmp);
776
777 MSG(NOTICE, "Capturing %dx%d @%.2f%s %s from %s\n", s->desc.width,
778 s->desc.height, s->desc.fps,
781
782 *state = s;
783 return VIDCAP_INIT_OK;
784
785error:
786 free(tmp);
787
789
790 return VIDCAP_INIT_FAIL;
791}
792
793static void vidcap_v4l2_done(void *state)
794{
795 struct vidcap_v4l2_state *s = (struct vidcap_v4l2_state *) state;
796
798}
799
801 struct v4l2_dispose_deq_buffer_data *data =
803
804 if (data) {
805 pthread_mutex_lock(&data->s->lock);
807 pthread_mutex_unlock(&data->s->lock);
808 pthread_cond_signal(&data->s->cv);
809 } else {
810 free(frame->tiles[0].data);
811 }
812
813 vf_free(frame);
814}
815
816static struct video_frame * vidcap_v4l2_grab(void *state, struct audio_frame **audio)
817{
818 struct vidcap_v4l2_state *s = (struct vidcap_v4l2_state *) state;
819 struct video_frame *out;
820
821 pthread_mutex_lock(&s->lock);
823 while (s->dequeued_buffers == s->buffer_count) { // we cannot dequeue any buffer
824 pthread_cond_wait(&s->cv, &s->lock);
826 }
827 pthread_mutex_unlock(&s->lock);
828
829 *audio = NULL;
830
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;
835
836 if(ioctl(s->fd, VIDIOC_DQBUF, &buf) != 0) {
837 log_perror(LOG_LEVEL_ERROR, MOD_NAME "Unable to dequeue buffer");
838 return NULL;
839 };
840
841 s->dequeued_buffers += 1;
842
843 out = vf_alloc_desc(s->desc);
845
846#ifdef HAVE_LIBV4LCONVERT
847 if (s->convert) {
848 out->callbacks.dispose_udata = NULL;
849 out->tiles[0].data = (char *) malloc(out->tiles[0].data_len);
850 int ret = v4lconvert_convert(s->convert,
851 &s->src_fmt, /* in */
852 &s->dst_fmt, /* in */
853 s->buffers[buf.index].start,
854 buf.bytesused,
855 (unsigned char *) out->tiles[0].data,
856 out->tiles[0].data_len);
857
858 // we do not need the driver buffer any more
859 if (ioctl(s->fd, VIDIOC_QBUF, &buf) != 0) {
860 log_perror(LOG_LEVEL_ERROR, "[V4L2 capture] Unable to enqueue buffer");
861 } else {
862 s->dequeued_buffers -= 1;
863 }
864
865 if(ret == -1) {
866 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Error converting video: %s\n", v4lconvert_get_error_message(s->convert));
868 return NULL;
869 }
870
871 out->tiles[0].data_len = ret;
872#else
873 if (0) {
874#endif // HAVE_LIBV4LCONVERT
875 } else {
876 struct v4l2_dispose_deq_buffer_data *frame_data =
877 malloc(sizeof(struct v4l2_dispose_deq_buffer_data));
878 frame_data->s = s;
879 memcpy(&frame_data->buf, &buf, sizeof(buf));
880 out->tiles[0].data = s->buffers[frame_data->buf.index].start;
881 out->tiles[0].data_len = frame_data->buf.bytesused;
882 out->callbacks.dispose_udata = frame_data;
883 }
884
885 s->frames++;
886
887 struct timeval t;
888 gettimeofday(&t, NULL);
889 double seconds = tv_diff(t, s->t0);
890 if (seconds >= 5) {
891 float fps = s->frames / seconds;
892 log_msg(LOG_LEVEL_INFO, "[V4L2 capture] %d frames in %g seconds = %g FPS\n", s->frames, seconds, fps);
893 s->t0 = t;
894 s->frames = 0;
895 }
896
897
898 return out;
899}
900
908
910// vi: set et sw=8:
convert_t convert
void ** state
struct video_frame * frame
const char * fmt
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)
static void show_help()
Definition wasapi.cpp:193
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_FG_RED
Definition color_out.h:50
#define TERM_RESET
Definition color_out.h:47
#define TRED(x)
Definition color_out.h:75
#define TBOLD(x)
Definition color_out.h:70
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
void log_perror(int level, const char *msg)
Definition debug.cpp:165
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define MSG(l, fmt,...)
Definition debug.h:96
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
#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
int count
Definition hd-rum.c:44
@ LIBRARY_CLASS_VIDEO_CAPTURE
Definition lib_common.h:78
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
void simple_linked_list_append(struct simple_linked_list *l, void *data)
Definition list.cpp:68
struct simple_linked_list * simple_linked_list_init(void)
Definition list.cpp:53
void simple_linked_list_destroy(struct simple_linked_list *l)
Definition list.cpp:58
void * simple_linked_list_pop(struct simple_linked_list *l)
Definition list.cpp:82
#define MIN(a, b)
Definition macros.h:63
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
Definition macros.h:138
#define IS_PREFIX(tok, key)
similar as above, but also key without a value is accepted (value optional)
Definition macros.h:142
const char * ug_strerror(int errnum)
Definition misc.cpp:203
enum openssl_mode mode
Option::OptType type
Definition settings.cpp:194
const char * param
Definition settings.cpp:195
const char * name
Definition settings.cpp:193
struct used to comunicate with audio capture/playback device
Definition types.h:99
Definition hd-rum.c:27
uint32_t numerator
Definition v4l2.c:515
uint32_t height
Definition v4l2.c:514
bool permissive
Definition v4l2.c:518
uint32_t width
Definition v4l2.c:513
char * dev_name
Definition v4l2.c:512
uint32_t denominator
Definition v4l2.c:516
codec_t v4l2_convert_to
Definition v4l2.c:519
uint32_t pixelformat
Definition v4l2.c:511
int buffer_count
Definition v4l2.c:517
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
struct vidcap_v4l2_state * s
Definition v4l2.c:111
struct v4l2_buffer buf
Definition v4l2.c:112
pthread_mutex_t lock
Definition v4l2.c:106
struct video_desc desc
Definition v4l2.c:87
struct timeval t0
Definition v4l2.c:99
struct v4l2_buffer_data buffers[MAX_BUF_COUNT]
Definition v4l2.c:90
_Bool permissive
do not fail if parameters (size, FPS...) not set exactly
Definition v4l2.c:92
struct v4l2_format dst_fmt
converted format if v4lconvert is used
Definition v4l2.c:97
pthread_cond_t cv
Definition v4l2.c:107
struct simple_linked_list * buffers_to_enqueue
Definition v4l2.c:104
struct v4l2_format src_fmt
captured format
Definition v4l2.c:96
int dequeued_buffers
Definition v4l2.c:105
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
enum interlacing_t interlacing
Definition types.h:184
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
void(* dispose)(struct video_frame *)
Definition types.h:245
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
struct video_frame_callbacks callbacks
Definition types.h:324
double tv_diff(struct timeval curr_time, struct timeval prev_time)
Definition tv.c:97
codec_t
Definition types.h:65
@ RGB
RGB 8-bit (packed into 24-bit word)
Definition types.h:80
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
@ VC_NONE
Definition types.h:67
static struct @67 v4l2_field_map[]
codec_t ug_codec
Definition v4l2_common.h:68
enum v4l2_field v4l_f
Definition v4l2_common.h:53
static struct @68 v4l2_ug_map[]
#define V4L2_PROBE_MAX
Definition v4l2_common.h:50
uint32_t v4l2_fcc
Definition v4l2_common.h:67
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)
Definition v4l2.c:358
static const struct video_capture_info vidcap_v4l2_info
Definition v4l2.c:901
static void print_fps(int fd, struct v4l2_frmivalenum *param)
Definition v4l2.c:168
static void vidcap_v4l2_done(void *state)
Definition v4l2.c:793
static void enqueue_all_finished_frames(struct vidcap_v4l2_state *s)
Definition v4l2.c:115
static void vidcap_v4l2_common_cleanup(struct vidcap_v4l2_state *s)
Definition v4l2.c:126
static void vidcap_v4l2_dispose_video_frame(struct video_frame *frame)
Definition v4l2.c:800
static void write_fcc(char *out, int pixelformat)
Definition v4l2.c:199
static void vidcap_v4l2_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
Definition v4l2.c:392
static bool parse_fmt(char *fmt, struct parsed_opts *opts)
Definition v4l2.c:523
static void write_mode(struct mode *m, int width, int height, unsigned tpf_num, unsigned tpf_denom, int pixelformat)
Definition v4l2.c:367
#define MOD_NAME
Definition v4l2.c:69
static struct video_frame * vidcap_v4l2_grab(void *state, struct audio_frame **audio)
Definition v4l2.c:816
static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
Definition v4l2.c:582
@ MAX_BUF_COUNT
Definition v4l2.c:67
@ DEFAULT_BUF_COUNT
Definition v4l2.c:66
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)
Definition v4l2.c:484
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)
Definition video_frame.h:76