v4l2: list available formats
authorLuca Barbato <lu_zero@gentoo.org>
Tue, 27 Dec 2011 05:31:41 +0000 (06:31 +0100)
committerLuca Barbato <lu_zero@gentoo.org>
Wed, 4 Jan 2012 12:10:20 +0000 (13:10 +0100)
Make use of the experimental framesize enumeration ioctl if available.

configure
doc/indevs.texi
libavdevice/v4l2.c

index 481f0ea..9bf65d2 100755 (executable)
--- 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"
index 4405a5b..e1b4ddd 100644 (file)
@@ -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.
index cde2f9f..2895a01 100644 (file)
 
 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 },
 };