Skip to content

Commit 21db4b7

Browse files
committed
v4l2: moved parsing to separate fn
1 parent 94dff54 commit 21db4b7

File tree

1 file changed

+113
-93
lines changed

1 file changed

+113
-93
lines changed

src/video_capture/v4l2.c

Lines changed: 113 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
#include "tv.h"
7373
#include "utils/color_out.h"
7474
#include "utils/list.h"
75+
#include "utils/macros.h"
7576
#include "utils/misc.h" // ug_strerror
7677
#include "v4l2_common.h"
7778
#include "video.h"
@@ -492,15 +493,83 @@ static _Bool v4l2_cap_verify_params(_Bool permissive, const struct v4l2_format *
492493
return 1;
493494
}
494495

496+
struct parsed_opts {
497+
uint32_t pixelformat;
498+
char *dev_name;
499+
uint32_t width;
500+
uint32_t height;
501+
uint32_t numerator;
502+
uint32_t denominator;
503+
int buffer_count;
504+
bool permissive;
505+
codec_t v4l2_convert_to;
506+
};
507+
508+
static bool
509+
parse_fmt(char *fmt, struct parsed_opts *opts)
510+
{
511+
char *save_ptr = NULL;
512+
char *item = NULL;;
513+
while ((item = strtok_r(fmt, ":", &save_ptr))) {
514+
fmt = NULL;
515+
if (strncmp(item, "dev=", strlen("dev=")) == 0 ||
516+
strncmp(item, "device=", strlen("device=")) == 0) {
517+
opts->dev_name = strchr(item, '=') + 1;
518+
} else if (strncmp(item, "fmt=", strlen("fmt=")) == 0 ||
519+
strncmp(item, "codec=", strlen("codec=")) == 0) {
520+
char *fmt = strchr(item, '=') + 1;
521+
union {
522+
uint32_t fourcc;
523+
char str[4];
524+
} str_to_uint = { .fourcc = 0 };
525+
memcpy(str_to_uint.str, fmt, MIN(strlen(fmt), 4));
526+
opts->pixelformat = str_to_uint.fourcc;
527+
} else if (strncmp(item, "size=", strlen("size=")) == 0) {
528+
if (strchr(item, 'x')) {
529+
opts->width = atoi(item + strlen("size="));
530+
opts->height = atoi(strchr(item, 'x') + 1);
531+
}
532+
} else if (strncmp(item, "tpf=", strlen("tpf=")) == 0) {
533+
opts->numerator = atoi(item + strlen("tpf="));
534+
opts->denominator = strchr(item, '/') == NULL
535+
? 1
536+
: atoi(strchr(item, '/') + 1);
537+
} else if (strncmp(item, "fps=", strlen("fps=")) == 0) {
538+
opts->denominator = atoi(item + strlen("fps="));
539+
opts->numerator = strchr(item, '/') == NULL
540+
? 1
541+
: atoi(strchr(item, '/') + 1);
542+
} else if (strncmp(item, "buffers=", strlen("buffers=")) == 0) {
543+
opts->buffer_count = atoi(item + strlen("buffers="));
544+
assert(opts->buffer_count <= MAX_BUF_COUNT);
545+
} else if (strstr(item, "convert=") == item) {
546+
#ifdef HAVE_LIBV4LCONVERT
547+
const char *codec = item + strlen("convert=");
548+
opts->v4l2_convert_to = get_codec_from_name(codec);
549+
if (opts->v4l2_convert_to == VIDEO_CODEC_NONE) {
550+
log_msg(LOG_LEVEL_ERROR,
551+
MOD_NAME "Unknown codec: %s\n",
552+
codec);
553+
return false;
554+
}
555+
#else
556+
MSG(ERROR, "v4lconvert support not compiled in!");
557+
return false;
558+
#endif
559+
} else if (strstr(item, "permissive") == item) {
560+
opts->permissive = 1;
561+
} else {
562+
MSG(ERROR, "Invalid configuration argument: %s\n",
563+
item);
564+
return false;
565+
}
566+
}
567+
return true;
568+
}
569+
495570
static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
496571
{
497-
const char *dev_name = NULL;
498-
uint32_t pixelformat = 0;
499-
uint32_t width = 0,
500-
height = 0;
501-
uint32_t numerator = 0,
502-
denominator = 0;
503-
codec_t v4l2_convert_to = VIDEO_CODEC_NONE;
572+
struct parsed_opts opts = { .buffer_count = DEFAULT_BUF_COUNT };
504573

505574
printf("vidcap_v4l2_init\n");
506575

@@ -519,7 +588,6 @@ static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
519588
printf("Unable to allocate v4l2 capture state\n");
520589
return VIDCAP_INIT_FAIL;
521590
}
522-
s->buffer_count = DEFAULT_BUF_COUNT;
523591
s->fd = -1;
524592
s->buffers_to_enqueue = simple_linked_list_init();
525593
pthread_mutex_init(&s->lock, NULL);
@@ -530,82 +598,24 @@ static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
530598
if(vidcap_params_get_fmt(params)) {
531599
tmp = strdup(vidcap_params_get_fmt(params));
532600
assert(tmp != NULL);
533-
char *init_fmt = tmp;
534-
char *save_ptr = NULL;
535-
char *item;
536-
while((item = strtok_r(init_fmt, ":", &save_ptr))) {
537-
if (strncmp(item, "dev=", strlen("dev=")) == 0
538-
|| strncmp(item, "device=", strlen("device=")) == 0) {
539-
dev_name = strchr(item, '=') + 1;
540-
} else if (strncmp(item, "fmt=", strlen("fmt=")) == 0
541-
|| strncmp(item, "codec=", strlen("codec=")) == 0) {
542-
char *fmt = strchr(item, '=') + 1;
543-
union {
544-
uint32_t fourcc;
545-
char str[4];
546-
} str_to_uint;
547-
int len = 4;
548-
if(strlen(fmt) < 4) len = strlen(fmt);
549-
memset(str_to_uint.str, 0, 4);
550-
memcpy(str_to_uint.str, fmt, len);
551-
pixelformat = str_to_uint.fourcc;
552-
} else if (strncmp(item, "size=",
553-
strlen("size=")) == 0) {
554-
if(strchr(item, 'x')) {
555-
width = atoi(item + strlen("size="));
556-
height = atoi(strchr(item, 'x') + 1);
557-
}
558-
} else if (strncmp(item, "tpf=", strlen("tpf=")) == 0) {
559-
numerator = atoi(item + strlen("tpf="));
560-
if (strchr(item, '/')) {
561-
denominator = atoi(strchr(item, '/') + 1);
562-
} else {
563-
denominator = 1;
564-
}
565-
} else if (strncmp(item, "fps=", strlen("fps=")) == 0) {
566-
denominator = atoi(item + strlen("fps="));
567-
if(strchr(item, '/')) {
568-
numerator = atoi(strchr(item, '/') + 1);
569-
} else {
570-
numerator = 1;
571-
}
572-
} else if (strncmp(item, "buffers=",
573-
strlen("buffers=")) == 0) {
574-
s->buffer_count = atoi(item + strlen("buffers="));
575-
assert (s->buffer_count <= MAX_BUF_COUNT);
576-
} else if (strstr(item, "convert=") == item) {
577-
#ifdef HAVE_LIBV4LCONVERT
578-
const char *codec = item + strlen("convert=");
579-
v4l2_convert_to = get_codec_from_name(codec);
580-
if (v4l2_convert_to == VIDEO_CODEC_NONE) {
581-
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unknown codec: %s\n", codec);
582-
goto error;
583-
}
584-
#else
585-
log_msg(LOG_LEVEL_ERROR, MOD_NAME "v4lconvert support not compiled in!");
586-
goto error;
587-
#endif
588-
} else if (strstr(item, "permissive") == item) {
589-
s->permissive = 1;
590-
} else {
591-
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Invalid configuration argument: %s\n",
592-
item);
593-
goto error;
594-
}
595-
init_fmt = NULL;
601+
if (!parse_fmt(tmp, &opts)) {
602+
goto error;
596603
}
597604
}
598605

606+
s->buffer_count = opts.buffer_count;
607+
s->permissive= opts.permissive;
608+
599609
static_assert(V4L2_PROBE_MAX < 100, "Pattern below has place only for 2 digits");
600610
char dev_name_try[] = "/dev/videoXX";
601-
if (dev_name != NULL) {
602-
s->fd = try_open_v4l2_device(LOG_LEVEL_ERROR, dev_name, V4L2_CAP_VIDEO_CAPTURE);
611+
if (opts.dev_name != NULL) {
612+
s->fd = try_open_v4l2_device(LOG_LEVEL_ERROR, opts.dev_name, V4L2_CAP_VIDEO_CAPTURE);
603613
} else {
604614
for (int i = 0; i < V4L2_PROBE_MAX; ++i) {
605615
snprintf(dev_name_try, sizeof dev_name_try, "/dev/video%d", i);
606616
s->fd = try_open_v4l2_device(LOG_LEVEL_WARNING, dev_name_try, V4L2_CAP_VIDEO_CAPTURE);
607617
if (s->fd != -1) {
608-
dev_name = dev_name_try;
618+
opts.dev_name = dev_name_try;
609619
break;
610620
}
611621
}
@@ -626,13 +636,13 @@ static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
626636
goto error;
627637
}
628638

629-
if (pixelformat) {
630-
fmt.fmt.pix.pixelformat = pixelformat;
639+
if (opts.pixelformat) {
640+
fmt.fmt.pix.pixelformat = opts.pixelformat;
631641
}
632642

633-
if(width != 0 && height != 0) {
634-
fmt.fmt.pix.width = width;
635-
fmt.fmt.pix.height = height;
643+
if (opts.width != 0 && opts.height != 0) {
644+
fmt.fmt.pix.width = opts.width;
645+
fmt.fmt.pix.height = opts.height;
636646
}
637647

638648
fmt.fmt.pix.field = V4L2_FIELD_ANY;
@@ -643,13 +653,17 @@ static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
643653
log_perror(LOG_LEVEL_ERROR, MOD_NAME "Unable to set video format");
644654
goto error;
645655
}
646-
if (numerator != 0 && denominator != 0) {
647-
stream_params.parm.capture.timeperframe.numerator = numerator;
648-
stream_params.parm.capture.timeperframe.denominator = denominator;
656+
if (opts.numerator != 0 && opts.denominator != 0) {
657+
stream_params.parm.capture.timeperframe.numerator =
658+
opts.numerator;
659+
stream_params.parm.capture.timeperframe.denominator =
660+
opts.denominator;
649661
}
650662
struct v4l2_streamparm req_stream_params = stream_params;
651-
if (numerator != 0 && denominator != 0 && ioctl(s->fd, VIDIOC_S_PARM, &stream_params) != 0) {
652-
log_perror(LOG_LEVEL_ERROR, MOD_NAME "Unable to set stream params");
663+
if (opts.numerator != 0 && opts.denominator != 0 &&
664+
ioctl(s->fd, VIDIOC_S_PARM, &stream_params) != 0) {
665+
log_perror(LOG_LEVEL_ERROR,
666+
MOD_NAME "Unable to set stream params");
653667
goto error;
654668
}
655669
if (!v4l2_cap_verify_params(s->permissive, &req_fmt, &fmt, &req_stream_params, &stream_params) && !s->permissive) {
@@ -673,28 +687,34 @@ static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
673687

674688
s->desc.tile_count = 1;
675689

676-
if (v4l2_convert_to == VIDEO_CODEC_NONE) {
690+
if (opts.v4l2_convert_to == VC_NONE) {
677691
s->desc.color_spec = get_v4l2_to_ug(fmt.fmt.pix.pixelformat);
678692
if (s->desc.color_spec == VIDEO_CODEC_NONE) {
679693
char fcc[5];
680694
memcpy(fcc, &fmt.fmt.pix.pixelformat, 4);
681695
fcc[4] = '\0';
682696
log_msg(LOG_LEVEL_WARNING, MOD_NAME "No mapping for FCC '%s', converting to RGB!\n", fcc);
683-
v4l2_convert_to = s->dst_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
697+
opts.v4l2_convert_to = s->dst_fmt.fmt.pix.pixelformat =
698+
V4L2_PIX_FMT_RGB24;
684699
}
685700
}
686-
if (v4l2_convert_to != VIDEO_CODEC_NONE) {
701+
if (opts.v4l2_convert_to != VC_NONE) {
687702
#ifdef HAVE_LIBV4LCONVERT
688-
s->dst_fmt.fmt.pix.pixelformat = get_ug_to_v4l2(v4l2_convert_to);
703+
s->dst_fmt.fmt.pix.pixelformat =
704+
get_ug_to_v4l2(opts.v4l2_convert_to);
689705
if (!v4lconvert_supported_dst_format(s->dst_fmt.fmt.pix.pixelformat)) {
690-
log_msg(LOG_LEVEL_WARNING, MOD_NAME "Conversion to %s doesn't seem to be supported by v4lconvert but proceeding as requested...\n", get_codec_name(v4l2_convert_to));
706+
MSG(WARNING,
707+
"Conversion to %s doesn't seem to be supported by "
708+
"v4lconvert but proceeding as requested...\n",
709+
get_codec_name(opts.v4l2_convert_to));
691710
}
692711

693712
if (s->dst_fmt.fmt.pix.pixelformat == 0) {
694-
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot find %s to V4L2 mapping!\n", get_codec_name(v4l2_convert_to));
713+
MSG(ERROR, "Cannot find %s to V4L2 mapping!\n",
714+
get_codec_name(opts.v4l2_convert_to));
695715
goto error;
696716
}
697-
s->desc.color_spec = v4l2_convert_to;
717+
s->desc.color_spec = opts.v4l2_convert_to;
698718
#endif
699719
}
700720

@@ -716,7 +736,7 @@ static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
716736

717737
#ifdef HAVE_LIBV4LCONVERT
718738
s->convert = NULL;
719-
if (v4l2_convert_to != VIDEO_CODEC_NONE) {
739+
if (opts.v4l2_convert_to != VC_NONE) {
720740
s->convert = v4lconvert_create(s->fd);
721741
}
722742
#endif
@@ -746,7 +766,7 @@ static int vidcap_v4l2_init(struct vidcap_params *params, void **state)
746766
MSG(NOTICE, "Capturing %dx%d @%.2f%s %s from %s\n", s->desc.width,
747767
s->desc.height, s->desc.fps,
748768
get_interlacing_suffix(s->desc.interlacing),
749-
get_codec_name(s->desc.color_spec), dev_name);
769+
get_codec_name(s->desc.color_spec), opts.dev_name);
750770

751771
*state = s;
752772
return VIDCAP_INIT_OK;

0 commit comments

Comments
 (0)