From d03c94a000b6fe8544b95aafd17ec030fab2813c Mon Sep 17 00:00:00 2001 From: fryshorts Date: Tue, 15 Jul 2014 20:29:14 +0200 Subject: [PATCH 1/6] Some minor code refactoring in v4l2 plugin Small code changes to decrease indentation a little. --- plugins/linux-v4l2/v4l2-input.c | 48 +++++++++++++++++---------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/plugins/linux-v4l2/v4l2-input.c b/plugins/linux-v4l2/v4l2-input.c index 2479922c5..9717418e2 100644 --- a/plugins/linux-v4l2/v4l2-input.c +++ b/plugins/linux-v4l2/v4l2-input.c @@ -291,35 +291,37 @@ static void v4l2_device_list(obs_property_t prop, obs_data_t settings) struct dstr device; bool first = true; + dirp = opendir("/sys/class/video4linux"); + if (!dirp) + return; + obs_property_list_clear(prop); dstr_init_copy(&device, "/dev/"); - dirp = opendir("/sys/class/video4linux"); - if (dirp) { - while ((dp = readdir(dirp)) != NULL) { - dstr_resize(&device, 5); - dstr_cat(&device, dp->d_name); - if ((fd = open(device.array, - O_RDWR | O_NONBLOCK)) == -1) { - continue; + while ((dp = readdir(dirp)) != NULL) { + dstr_resize(&device, 5); + dstr_cat(&device, dp->d_name); + + if ((fd = open(device.array, O_RDWR | O_NONBLOCK)) == -1) + continue; + + if (ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) + continue; + + if (video_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { + obs_property_list_add_string(prop, + (char *) video_cap.card, + device.array); + if (first) { + obs_data_setstring(settings, + "device_id", device.array); + first = false; } - if (ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) { - continue; - } else if (video_cap.capabilities & - V4L2_CAP_VIDEO_CAPTURE) { - obs_property_list_add_string(prop, - (char *) video_cap.card, - device.array); - if (first) { - obs_data_setstring(settings, - "device_id", device.array); - first = false; - } - } - close(fd); } - closedir(dirp); + close(fd); } + + closedir(dirp); dstr_free(&device); } From d8f3761cada5fc797124f40709e5379278473294 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Tue, 15 Jul 2014 20:45:42 +0200 Subject: [PATCH 2/6] Fix a possibly left open file descriptor in v4l2 plugin --- plugins/linux-v4l2/v4l2-input.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/linux-v4l2/v4l2-input.c b/plugins/linux-v4l2/v4l2-input.c index 9717418e2..d4ab60ce2 100644 --- a/plugins/linux-v4l2/v4l2-input.c +++ b/plugins/linux-v4l2/v4l2-input.c @@ -299,16 +299,18 @@ static void v4l2_device_list(obs_property_t prop, obs_data_t settings) dstr_init_copy(&device, "/dev/"); while ((dp = readdir(dirp)) != NULL) { + if (dp->d_type == DT_DIR) + continue; + dstr_resize(&device, 5); dstr_cat(&device, dp->d_name); if ((fd = open(device.array, O_RDWR | O_NONBLOCK)) == -1) continue; - if (ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) - continue; - - if (video_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { + if (ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) { + + } else if (video_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { obs_property_list_add_string(prop, (char *) video_cap.card, device.array); @@ -318,6 +320,7 @@ static void v4l2_device_list(obs_property_t prop, obs_data_t settings) first = false; } } + close(fd); } From 720f159274d31689b6ef2cf53b6715fe639d0317 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Tue, 15 Jul 2014 20:51:13 +0200 Subject: [PATCH 3/6] Use macro for prefixing log messages in v4l2 plugin --- plugins/linux-v4l2/v4l2-input.c | 41 +++++++++++++++++---------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/plugins/linux-v4l2/v4l2-input.c b/plugins/linux-v4l2/v4l2-input.c index d4ab60ce2..6f1b92a06 100644 --- a/plugins/linux-v4l2/v4l2-input.c +++ b/plugins/linux-v4l2/v4l2-input.c @@ -39,6 +39,8 @@ along with this program. If not, see . #define timeval2ns(tv) \ (((uint64_t) tv.tv_sec * 1000000000) + ((uint64_t) tv.tv_usec * 1000)) +#define blog(level, msg, ...) blog(level, "v4l2-input: " msg, ##__VA_ARGS__) + struct v4l2_buffer_data { size_t length; void *start; @@ -105,14 +107,14 @@ static int_fast32_t v4l2_start_capture(struct v4l2_data *data) buf.index = i; if (ioctl(data->dev, VIDIOC_QBUF, &buf) < 0) { - blog(LOG_ERROR, "v4l2-input: unable to queue buffer"); + blog(LOG_ERROR, "unable to queue buffer"); return -1; } } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(data->dev, VIDIOC_STREAMON, &type) < 0) { - blog(LOG_ERROR, "v4l2-input: unable to start stream"); + blog(LOG_ERROR, "unable to start stream"); return -1; } @@ -127,7 +129,7 @@ static int_fast32_t v4l2_stop_capture(struct v4l2_data *data) enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(data->dev, VIDIOC_STREAMOFF, &type) < 0) { - blog(LOG_ERROR, "v4l2-input: unable to stop stream"); + blog(LOG_ERROR, "unable to stop stream"); } return 0; @@ -145,12 +147,12 @@ static int_fast32_t v4l2_create_mmap(struct v4l2_data *data) req.memory = V4L2_MEMORY_MMAP; if (ioctl(data->dev, VIDIOC_REQBUFS, &req) < 0) { - blog(LOG_DEBUG, "v4l2-input: request for buffers failed !"); + blog(LOG_DEBUG, "request for buffers failed !"); return -1; } if (req.count < 2) { - blog(LOG_DEBUG, "v4l2-input: not enough memory !"); + blog(LOG_DEBUG, "not enough memory !"); return -1; } @@ -165,7 +167,7 @@ static int_fast32_t v4l2_create_mmap(struct v4l2_data *data) buf.index = i; if (ioctl(data->dev, VIDIOC_QUERYBUF, &buf) < 0) { - blog(LOG_ERROR, "v4l2-input: failed to query buffer"); + blog(LOG_ERROR, "failed to query buffer"); return -1; } @@ -175,7 +177,7 @@ static int_fast32_t v4l2_create_mmap(struct v4l2_data *data) data->dev, buf.m.offset); if (data->buf[i].start == MAP_FAILED) { - blog(LOG_ERROR, "v4l2-input: mmap for buffer failed"); + blog(LOG_ERROR, "mmap for buffer failed"); return -1; } } @@ -224,10 +226,10 @@ static void *v4l2_thread(void *vptr) if (r < 0) { if (errno == EINTR) continue; - blog(LOG_DEBUG, "v4l2-input: select failed"); + blog(LOG_DEBUG, "select failed"); break; } else if (r == 0) { - blog(LOG_DEBUG, "v4l2-input: select timeout"); + blog(LOG_DEBUG, "select timeout"); continue; } @@ -237,7 +239,7 @@ static void *v4l2_thread(void *vptr) if (ioctl(data->dev, VIDIOC_DQBUF, &buf) < 0) { if (errno == EAGAIN) continue; - blog(LOG_DEBUG, "v4l2-input: failed to dequeue buffer"); + blog(LOG_DEBUG, "failed to dequeue buffer"); break; } @@ -254,7 +256,7 @@ static void *v4l2_thread(void *vptr) obs_source_output_video(data->source, &out); if (ioctl(data->dev, VIDIOC_QBUF, &buf) < 0) { - blog(LOG_DEBUG, "v4l2-input: failed to enqueue buffer"); + blog(LOG_DEBUG, "failed to enqueue buffer"); break; } @@ -309,7 +311,7 @@ static void v4l2_device_list(obs_property_t prop, obs_data_t settings) continue; if (ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) { - + } else if (video_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { obs_property_list_add_string(prop, (char *) video_cap.card, @@ -546,8 +548,7 @@ static void v4l2_init(struct v4l2_data *data) data->dev = open(data->device, O_RDWR | O_NONBLOCK); if (data->dev == -1) { - blog(LOG_ERROR, "v4l2-input: Unable to open device: %s", - data->device); + blog(LOG_ERROR, "Unable to open device: %s", data->device); goto fail; } @@ -558,7 +559,7 @@ static void v4l2_init(struct v4l2_data *data) fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (ioctl(data->dev, VIDIOC_S_FMT, &fmt) < 0) { - blog(LOG_DEBUG, "v4l2-input: unable to set format"); + blog(LOG_DEBUG, "unable to set format"); goto fail; } data->pixelformat = fmt.fmt.pix.pixelformat; @@ -570,17 +571,17 @@ static void v4l2_init(struct v4l2_data *data) par.parm.capture.timeperframe.denominator = data->fps_denominator; if (ioctl(data->dev, VIDIOC_S_PARM, &par) < 0) { - blog(LOG_DEBUG, "v4l2-input: unable to set params"); + blog(LOG_DEBUG, "unable to set params"); goto fail; } data->fps_numerator = par.parm.capture.timeperframe.numerator; data->fps_denominator = par.parm.capture.timeperframe.denominator; data->linesize = fmt.fmt.pix.bytesperline; - blog(LOG_DEBUG, "v4l2-input: Linesize: %"PRIuFAST32, data->linesize); + blog(LOG_DEBUG, "Linesize: %"PRIuFAST32, data->linesize); if (v4l2_create_mmap(data) < 0) { - blog(LOG_ERROR, "v4l2-input: failed to map buffers"); + blog(LOG_ERROR, "failed to map buffers"); goto fail; } @@ -590,7 +591,7 @@ static void v4l2_init(struct v4l2_data *data) goto fail; return; fail: - blog(LOG_DEBUG, "v4l2-input: initialization failed"); + blog(LOG_DEBUG, "initialization failed"); v4l2_terminate(data); } @@ -656,7 +657,7 @@ static void *v4l2_create(obs_data_t settings, obs_source_t source) data->source = source; v4l2_update(data, settings); - blog(LOG_DEBUG, "v4l2-input: New input created"); + blog(LOG_DEBUG, "New input created"); return data; } From 27297e7009d44f465be8c7f9a6219e94df920a46 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Tue, 15 Jul 2014 21:40:52 +0200 Subject: [PATCH 4/6] Add more logging to v4l2 plugin. This adds some mostly user focused logging statements. --- plugins/linux-v4l2/v4l2-input.c | 36 +++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/plugins/linux-v4l2/v4l2-input.c b/plugins/linux-v4l2/v4l2-input.c index 6f1b92a06..67788d8c7 100644 --- a/plugins/linux-v4l2/v4l2-input.c +++ b/plugins/linux-v4l2/v4l2-input.c @@ -209,6 +209,9 @@ static void *v4l2_thread(void *vptr) if (v4l2_start_capture(data) < 0) goto exit; + data->frames = 0; + blog(LOG_INFO, "Started recording from %s", data->device); + while (os_event_try(data->event) == EAGAIN) { int r; fd_set fds; @@ -263,6 +266,9 @@ static void *v4l2_thread(void *vptr) data->frames++; } + blog(LOG_INFO, "Stopped recording from %s after %"PRIu64" frames", + data->device, data->frames); + exit: v4l2_stop_capture(data); return NULL; @@ -307,11 +313,14 @@ static void v4l2_device_list(obs_property_t prop, obs_data_t settings) dstr_resize(&device, 5); dstr_cat(&device, dp->d_name); - if ((fd = open(device.array, O_RDWR | O_NONBLOCK)) == -1) + if ((fd = open(device.array, O_RDWR | O_NONBLOCK)) == -1) { + blog(LOG_INFO, "Unable to open %s", device.array); continue; + } if (ioctl(fd, VIDIOC_QUERYCAP, &video_cap) == -1) { - + blog(LOG_INFO, "Failed to query capabilities for %s", + device.array); } else if (video_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { obs_property_list_add_string(prop, (char *) video_cap.card, @@ -321,6 +330,12 @@ static void v4l2_device_list(obs_property_t prop, obs_data_t settings) "device_id", device.array); first = false; } + blog(LOG_INFO, "Found device '%s' at %s", + video_cap.card, device.array); + } + else { + blog(LOG_INFO, "%s seems to not support video capture", + device.array); } close(fd); @@ -347,6 +362,11 @@ static void v4l2_format_list(int dev, obs_property_t prop) obs_property_list_add_int(prop, (char *) fmt.description, fmt.pixelformat); + blog(LOG_INFO, "Pixelformat: %s (available)", + (char *) fmt.description); + } else { + blog(LOG_INFO, "Pixelformat: %s (unavailable)", + (char *) fmt.description); } fmt.index++; } @@ -374,6 +394,12 @@ static void v4l2_resolution_list(int dev, uint_fast32_t pixelformat, frmsize.discrete.height)); frmsize.index++; } + + if (frmsize.type != V4L2_FRMSIZE_TYPE_DISCRETE) { + blog(LOG_INFO, "Stepwise and Continuous framesizes " + "are currently not supported"); + } + dstr_free(&buffer); } @@ -402,6 +428,12 @@ static void v4l2_framerate_list(int dev, uint_fast32_t pixelformat, obs_property_list_add_int(prop, buffer.array, pack); frmival.index++; } + + if (frmival.type != V4L2_FRMIVAL_TYPE_DISCRETE) { + blog(LOG_INFO, "Stepwise and Continuous framerates " + "are currently not supported"); + } + dstr_free(&buffer); } From ba3c093156feb014e3c6e6996d27c01d03177d32 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Tue, 15 Jul 2014 23:23:05 +0200 Subject: [PATCH 5/6] Add fallback sizes and framerates to v4l2 plugin. Until a proper fix is found to support devices that use stepwise or continuous values for framesize and framerate this adds fixed values that can be selected. For devices that support discrete values those are still queried and used. --- plugins/linux-v4l2/v4l2-input.c | 126 ++++++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 21 deletions(-) diff --git a/plugins/linux-v4l2/v4l2-input.c b/plugins/linux-v4l2/v4l2-input.c index 67788d8c7..2fcc20812 100644 --- a/plugins/linux-v4l2/v4l2-input.c +++ b/plugins/linux-v4l2/v4l2-input.c @@ -92,6 +92,57 @@ static void unpack_tuple(int *a, int *b, int packed) *b = packed & 0xffff; } +/* fixed framesizes as fallback */ +static int fixed_framesizes[] = +{ + /* 4:3 */ + 160<<16 | 120, + 320<<16 | 240, + 480<<16 | 320, + 640<<16 | 480, + 800<<16 | 600, + 1024<<16 | 768, + 1280<<16 | 960, + 1440<<16 | 1050, + 1440<<16 | 1080, + 1600<<16 | 1200, + + /* 16:9 */ + 640<<16 | 360, + 960<<16 | 540, + 1280<<16 | 720, + 1600<<16 | 900, + 1920<<16 | 1080, + 1920<<16 | 1200, + + /* tv */ + 432<<16 | 520, + 480<<16 | 320, + 480<<16 | 530, + 486<<16 | 440, + 576<<16 | 310, + 576<<16 | 520, + 576<<16 | 570, + 1024<<16 | 576, + + 0 +}; + +/* fixed framerates as fallback */ +static int fixed_framerates[] = +{ + 1<<16 | 60, + 1<<16 | 50, + 1<<16 | 30, + 1<<16 | 25, + 1<<16 | 20, + 1<<16 | 15, + 1<<16 | 10, + 1<<16 | 5, + + 0 +}; + /* * start capture */ @@ -304,6 +355,7 @@ static void v4l2_device_list(obs_property_t prop, obs_data_t settings) return; obs_property_list_clear(prop); + dstr_init_copy(&device, "/dev/"); while ((dp = readdir(dirp)) != NULL) { @@ -386,18 +438,34 @@ static void v4l2_resolution_list(int dev, uint_fast32_t pixelformat, obs_property_list_clear(prop); - while (ioctl(dev, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0) { - dstr_printf(&buffer, "%dx%d", frmsize.discrete.width, - frmsize.discrete.height); - obs_property_list_add_int(prop, buffer.array, - pack_tuple(frmsize.discrete.width, - frmsize.discrete.height)); - frmsize.index++; - } + ioctl(dev, VIDIOC_ENUM_FRAMESIZES, &frmsize); - if (frmsize.type != V4L2_FRMSIZE_TYPE_DISCRETE) { + switch(frmsize.type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + while (ioctl(dev, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0) { + dstr_printf(&buffer, "%dx%d", frmsize.discrete.width, + frmsize.discrete.height); + obs_property_list_add_int(prop, buffer.array, + pack_tuple(frmsize.discrete.width, + frmsize.discrete.height)); + frmsize.index++; + } + break; + default: blog(LOG_INFO, "Stepwise and Continuous framesizes " - "are currently not supported"); + "are currently hardcoded"); + + for (uint_fast32_t i = 0; ; ++i) { + int packed = fixed_framesizes[i]; + if (!packed) + break; + int width; + int height; + unpack_tuple(&width, &height, packed); + dstr_printf(&buffer, "%dx%d", width, height); + obs_property_list_add_int(prop, buffer.array, packed); + } + break; } dstr_free(&buffer); @@ -419,19 +487,35 @@ static void v4l2_framerate_list(int dev, uint_fast32_t pixelformat, obs_property_list_clear(prop); - while (ioctl(dev, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) == 0) { - float fps = (float) frmival.discrete.denominator / - frmival.discrete.numerator; - int pack = pack_tuple(frmival.discrete.numerator, - frmival.discrete.denominator); - dstr_printf(&buffer, "%.2f", fps); - obs_property_list_add_int(prop, buffer.array, pack); - frmival.index++; - } + ioctl(dev, VIDIOC_ENUM_FRAMEINTERVALS, &frmival); - if (frmival.type != V4L2_FRMIVAL_TYPE_DISCRETE) { + switch(frmival.type) { + case V4L2_FRMIVAL_TYPE_DISCRETE: + while (ioctl(dev, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) == 0) { + float fps = (float) frmival.discrete.denominator / + frmival.discrete.numerator; + int pack = pack_tuple(frmival.discrete.numerator, + frmival.discrete.denominator); + dstr_printf(&buffer, "%.2f", fps); + obs_property_list_add_int(prop, buffer.array, pack); + frmival.index++; + } + break; + default: blog(LOG_INFO, "Stepwise and Continuous framerates " - "are currently not supported"); + "are currently hardcoded"); + for (uint_fast32_t i = 0; ; ++i) { + int packed = fixed_framerates[i]; + if (!packed) + break; + int num; + int denom; + unpack_tuple(&num, &denom, packed); + float fps = (float) denom / num; + dstr_printf(&buffer, "%.2f", fps); + obs_property_list_add_int(prop, buffer.array, packed); + } + break; } dstr_free(&buffer); From 87a527701a7575b6af606d61392242d2da9f2fc9 Mon Sep 17 00:00:00 2001 From: fryshorts Date: Wed, 16 Jul 2014 23:41:38 +0200 Subject: [PATCH 6/6] Use default color space in v4l2 plugin --- plugins/linux-v4l2/v4l2-input.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/linux-v4l2/v4l2-input.c b/plugins/linux-v4l2/v4l2-input.c index 2fcc20812..6d41d7a8a 100644 --- a/plugins/linux-v4l2/v4l2-input.c +++ b/plugins/linux-v4l2/v4l2-input.c @@ -297,9 +297,9 @@ static void *v4l2_thread(void *vptr) break; } - video_format_get_parameters(VIDEO_CS_709, VIDEO_RANGE_PARTIAL, - out.color_matrix, out.color_range_min, - out.color_range_max); + video_format_get_parameters(VIDEO_CS_DEFAULT, + VIDEO_RANGE_PARTIAL, out.color_matrix, + out.color_range_min, out.color_range_max); out.data[0] = (uint8_t *) data->buf[buf.index].start; out.linesize[0] = data->linesize; out.width = data->width;