diff options
author | Lukasz Marek <lukasz.m.luki2@gmail.com> | 2014-12-21 22:37:18 +0100 |
---|---|---|
committer | Lukasz Marek <lukasz.m.luki2@gmail.com> | 2015-01-11 18:58:33 +0100 |
commit | ea0ac11f1bf1909f369a9d7d2a26709412fc55f5 (patch) | |
tree | f1fc8c2c7f1b7f4a68246cb71819eff51ec7faf6 /libavdevice/v4l2.c | |
parent | 44e6eeb30de8e2d20db56284984da4615763525c (diff) | |
download | ffmpeg-ea0ac11f1bf1909f369a9d7d2a26709412fc55f5.tar.gz |
lavd/v4l2: implement list device callback
Signed-off-by: Lukasz Marek <lukasz.m.luki2@gmail.com>
Diffstat (limited to 'libavdevice/v4l2.c')
-rw-r--r-- | libavdevice/v4l2.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c index 29699808d5..8337cf5fc5 100644 --- a/libavdevice/v4l2.c +++ b/libavdevice/v4l2.c @@ -31,6 +31,7 @@ */ #include "v4l2-common.h" +#include <dirent.h> #if CONFIG_LIBV4L2 #include <libv4l2.h> @@ -1006,6 +1007,81 @@ static int v4l2_read_close(AVFormatContext *ctx) return 0; } +static int v4l2_is_v4l_dev(const char *name) +{ + return !strncmp(name, "video", 5) || + !strncmp(name, "radio", 5) || + !strncmp(name, "vbi", 3) || + !strncmp(name, "v4l-subdev", 10); +} + +static int v4l2_get_device_list(AVFormatContext *ctx, AVDeviceInfoList *device_list) +{ + struct video_data *s = ctx->priv_data; + DIR *dir; + struct dirent *entry; + AVDeviceInfo *device = NULL; + struct v4l2_capability cap; + int ret = 0; + + if (!device_list) + return AVERROR(EINVAL); + + dir = opendir("/dev"); + if (!dir) { + ret = AVERROR(errno); + av_log(ctx, AV_LOG_ERROR, "Couldn't open the directory: %s\n", av_err2str(ret)); + return ret; + } + while ((entry = readdir(dir))) { + if (!v4l2_is_v4l_dev(entry->d_name)) + continue; + + snprintf(ctx->filename, sizeof(ctx->filename), "/dev/%s", entry->d_name); + if ((s->fd = device_open(ctx)) < 0) + continue; + + if (v4l2_ioctl(s->fd, VIDIOC_QUERYCAP, &cap) < 0) { + ret = AVERROR(errno); + av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYCAP): %s\n", av_err2str(ret)); + goto fail; + } + + device = av_mallocz(sizeof(AVDeviceInfo)); + if (!device) { + ret = AVERROR(ENOMEM); + goto fail; + } + device->device_name = av_strdup(ctx->filename); + device->device_description = av_strdup(cap.card); + if (!device->device_name || !device->device_description) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if ((ret = av_dynarray_add_nofree(&device_list->devices, + &device_list->nb_devices, device)) < 0) + goto fail; + + v4l2_close(s->fd); + s->fd = -1; + continue; + + fail: + if (device) { + av_freep(&device->device_name); + av_freep(&device->device_description); + av_freep(&device); + } + if (s->fd >= 0) + v4l2_close(s->fd); + s->fd = -1; + break; + } + closedir(dir); + return ret; +} + #define OFFSET(x) offsetof(struct video_data, x) #define DEC AV_OPT_FLAG_DECODING_PARAM @@ -1050,6 +1126,7 @@ AVInputFormat ff_v4l2_demuxer = { .read_header = v4l2_read_header, .read_packet = v4l2_read_packet, .read_close = v4l2_read_close, + .get_device_list = v4l2_get_device_list, .flags = AVFMT_NOFILE, .priv_class = &v4l2_class, }; |