Commit a6a4793d authored by Luca Barbato's avatar Luca Barbato

v4l2: list available formats

Make use of the experimental framesize enumeration ioctl if available.
parent cd2bbad3
...@@ -1135,6 +1135,7 @@ HAVE_LIST=" ...@@ -1135,6 +1135,7 @@ HAVE_LIST="
struct_sockaddr_in6 struct_sockaddr_in6
struct_sockaddr_sa_len struct_sockaddr_sa_len
struct_sockaddr_storage struct_sockaddr_storage
struct_v4l2_frmivalenum_discrete
symver symver
symver_asm_label symver_asm_label
symver_gnu_asm symver_gnu_asm
...@@ -2993,6 +2994,8 @@ texi2html -version > /dev/null 2>&1 && enable texi2html || disable texi2html ...@@ -2993,6 +2994,8 @@ texi2html -version > /dev/null 2>&1 && enable texi2html || disable texi2html
check_header linux/fb.h check_header linux/fb.h
check_header linux/videodev.h check_header linux/videodev.h
check_header linux/videodev2.h check_header linux/videodev2.h
check_struct linux/videodev2.h "struct v4l2_frmivalenum" discrete
check_header sys/videoio.h check_header sys/videoio.h
check_func_headers "windows.h vfw.h" capCreateCaptureWindow "$vfwcap_indev_extralibs" check_func_headers "windows.h vfw.h" capCreateCaptureWindow "$vfwcap_indev_extralibs"
......
...@@ -267,7 +267,7 @@ the device. ...@@ -267,7 +267,7 @@ the device.
Video4Linux and Video4Linux2 devices only support a limited set of Video4Linux and Video4Linux2 devices only support a limited set of
@var{width}x@var{height} sizes and framerates. You can check which are @var{width}x@var{height} sizes and framerates. You can check which are
supported for example with the command @file{dov4l} for Video4Linux 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 If the size for the device is set to 0x0, the input device will
try to autodetect the size to use. try to autodetect the size to use.
......
...@@ -51,6 +51,10 @@ ...@@ -51,6 +51,10 @@
static const int desired_video_buffers = 256; static const int desired_video_buffers = 256;
#define V4L_ALLFORMATS 3
#define V4L_RAWFORMATS 1
#define V4L_COMPFORMATS 2
struct video_data { struct video_data {
AVClass *class; AVClass *class;
int fd; int fd;
...@@ -65,8 +69,10 @@ struct video_data { ...@@ -65,8 +69,10 @@ struct video_data {
unsigned int *buf_len; unsigned int *buf_len;
char *standard; char *standard;
int channel; 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. */ char *pixel_format; /**< Set by a private option. */
int list_format; /**< Set by a private option. */
char *framerate; /**< 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) ...@@ -258,6 +264,69 @@ static enum CodecID fmt_v4l2codec(uint32_t v4l2_fmt)
return CODEC_ID_NONE; 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) static int mmap_init(AVFormatContext *ctx)
{ {
struct video_data *s = ctx->priv_data; struct video_data *s = ctx->priv_data;
...@@ -621,6 +690,12 @@ static int v4l2_read_header(AVFormatContext *s1, AVFormatParameters *ap) ...@@ -621,6 +690,12 @@ static int v4l2_read_header(AVFormatContext *s1, AVFormatParameters *ap)
goto out; 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 */ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
if (s->video_size && if (s->video_size &&
...@@ -629,12 +704,18 @@ static int v4l2_read_header(AVFormatContext *s1, AVFormatParameters *ap) ...@@ -629,12 +704,18 @@ static int v4l2_read_header(AVFormatContext *s1, AVFormatParameters *ap)
s->video_size); s->video_size);
goto out; goto out;
} }
if (s->pixel_format &&
(pix_fmt = av_get_pix_fmt(s->pixel_format)) == PIX_FMT_NONE) { if (s->pixel_format) {
av_log(s1, AV_LOG_ERROR, "No such pixel format: %s.\n",
s->pixel_format); pix_fmt = av_get_pix_fmt(s->pixel_format);
res = AVERROR(EINVAL);
goto out; 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) { if (!s->width && !s->height) {
...@@ -737,6 +818,10 @@ static const AVOption options[] = { ...@@ -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 }, { "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 }, { "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 }, { "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 }, { NULL },
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment