From a6a4793d045cda277f0ec4579d206b36e3cf90b6 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Tue, 27 Dec 2011 06:31:41 +0100 Subject: [PATCH] v4l2: list available formats Make use of the experimental framesize enumeration ioctl if available. --- configure | 3 ++ doc/indevs.texi | 2 +- libavdevice/v4l2.c | 99 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/configure b/configure index 481f0eacaf..9bf65d23cc 100755 --- a/configure +++ b/configure @@ -1135,6 +1135,7 @@ HAVE_LIST=" struct_sockaddr_in6 struct_sockaddr_sa_len struct_sockaddr_storage + struct_v4l2_frmivalenum_discrete symver symver_asm_label symver_gnu_asm @@ -2993,6 +2994,8 @@ texi2html -version > /dev/null 2>&1 && enable texi2html || disable texi2html check_header linux/fb.h check_header linux/videodev.h check_header linux/videodev2.h +check_struct linux/videodev2.h "struct v4l2_frmivalenum" discrete + check_header sys/videoio.h check_func_headers "windows.h vfw.h" capCreateCaptureWindow "$vfwcap_indev_extralibs" diff --git a/doc/indevs.texi b/doc/indevs.texi index 4405a5b0a1..e1b4dddbc5 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -267,7 +267,7 @@ the device. Video4Linux and Video4Linux2 devices only support a limited set of @var{width}x@var{height} sizes and framerates. You can check which are supported for example with the command @file{dov4l} for Video4Linux -devices and the command @file{v4l-info} for Video4Linux2 devices. +devices and using @command{-list_formats all} for Video4Linux2 devices. If the size for the device is set to 0x0, the input device will try to autodetect the size to use. diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c index cde2f9f317..2895a01824 100644 --- a/libavdevice/v4l2.c +++ b/libavdevice/v4l2.c @@ -51,6 +51,10 @@ static const int desired_video_buffers = 256; +#define V4L_ALLFORMATS 3 +#define V4L_RAWFORMATS 1 +#define V4L_COMPFORMATS 2 + struct video_data { AVClass *class; int fd; @@ -65,8 +69,10 @@ struct video_data { unsigned int *buf_len; char *standard; int channel; - char *video_size; /**< String describing video size, set by a private option. */ + char *video_size; /**< String describing video size, + set by a private option. */ char *pixel_format; /**< Set by a private option. */ + int list_format; /**< Set by a private option. */ char *framerate; /**< Set by a private option. */ }; @@ -258,6 +264,69 @@ static enum CodecID fmt_v4l2codec(uint32_t v4l2_fmt) return CODEC_ID_NONE; } +#if HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE +static void list_framesizes(AVFormatContext *ctx, int fd, uint32_t pixelformat) +{ + struct v4l2_frmsizeenum vfse = { .pixel_format = pixelformat }; + + while(!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) { + switch (vfse.type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + av_log(ctx, AV_LOG_INFO, " %ux%u", + vfse.discrete.width, vfse.discrete.height); + break; + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + case V4L2_FRMSIZE_TYPE_STEPWISE: + av_log(ctx, AV_LOG_INFO, " {%u-%u, %u}x{%u-%u, %u}", + vfse.stepwise.min_width, + vfse.stepwise.max_width, + vfse.stepwise.step_width, + vfse.stepwise.min_height, + vfse.stepwise.max_height, + vfse.stepwise.step_height); + } + vfse.index++; + } +} +#endif + +static void list_formats(AVFormatContext *ctx, int fd, int type) +{ + struct v4l2_fmtdesc vfd = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; + + while(!ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) { + enum CodecID codec_id = fmt_v4l2codec(vfd.pixelformat); + enum PixelFormat pix_fmt = fmt_v4l2ff(vfd.pixelformat, codec_id); + + vfd.index++; + + if (!(vfd.flags & V4L2_FMT_FLAG_COMPRESSED) && + type & V4L_RAWFORMATS) { + const char *fmt_name = av_get_pix_fmt_name(pix_fmt); + av_log(ctx, AV_LOG_INFO, "R : %9s : %20s :", + fmt_name ? fmt_name : "Unsupported", + vfd.description); + } else if (vfd.flags & V4L2_FMT_FLAG_COMPRESSED && + type & V4L_COMPFORMATS) { + AVCodec *codec = avcodec_find_encoder(codec_id); + av_log(ctx, AV_LOG_INFO, "C : %9s : %20s :", + codec ? codec->name : "Unsupported", + vfd.description); + } else { + continue; + } + + if (vfd.flags & V4L2_FMT_FLAG_EMULATED) { + av_log(ctx, AV_LOG_WARNING, "%s", "Emulated"); + continue; + } +#if HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE + list_framesizes(ctx, fd, vfd.pixelformat); +#endif + av_log(ctx, AV_LOG_INFO, "\n"); + } +} + static int mmap_init(AVFormatContext *ctx) { struct video_data *s = ctx->priv_data; @@ -621,6 +690,12 @@ static int v4l2_read_header(AVFormatContext *s1, AVFormatParameters *ap) goto out; } + if (s->list_format) { + list_formats(s1, s->fd, s->list_format); + res = AVERROR_EXIT; + goto out; + } + avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ if (s->video_size && @@ -629,12 +704,18 @@ static int v4l2_read_header(AVFormatContext *s1, AVFormatParameters *ap) s->video_size); goto out; } - if (s->pixel_format && - (pix_fmt = av_get_pix_fmt(s->pixel_format)) == PIX_FMT_NONE) { - av_log(s1, AV_LOG_ERROR, "No such pixel format: %s.\n", - s->pixel_format); - res = AVERROR(EINVAL); - goto out; + + if (s->pixel_format) { + + pix_fmt = av_get_pix_fmt(s->pixel_format); + + if (pix_fmt == PIX_FMT_NONE) { + av_log(s1, AV_LOG_ERROR, "No such pixel format: %s.\n", + s->pixel_format); + + res = AVERROR(EINVAL); + goto out; + } } if (!s->width && !s->height) { @@ -737,6 +818,10 @@ static const AVOption options[] = { { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, { "pixel_format", "", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, + { "list_formats", "List available formats and exit", OFFSET(list_format), AV_OPT_TYPE_INT, {.dbl = 0 }, 0, INT_MAX, DEC, "list_formats" }, + { "all", "Show all available formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.dbl = V4L_ALLFORMATS }, 0, INT_MAX, DEC, "list_formats" }, + { "raw", "Show only non-compressed formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.dbl = V4L_RAWFORMATS }, 0, INT_MAX, DEC, "list_formats" }, + { "compressed", "Show only compressed formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.dbl = V4L_COMPFORMATS }, 0, INT_MAX, DEC, "list_formats" }, { NULL }, };