[FFmpeg-devel] [PATCH 8/8] tools: add device_capabilities testing tool

Lukasz Marek lukasz.m.luki at gmail.com
Sat Feb 22 23:33:42 CET 2014


tool allows to test implementations of device caps API.

Signed-off-by: Lukasz Marek <lukasz.m.luki at gmail.com>
---
 .gitignore                  |   1 +
 Makefile                    |   4 +-
 tools/device_capabilities.c | 319 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 323 insertions(+), 1 deletion(-)
 create mode 100644 tools/device_capabilities.c

diff --git a/.gitignore b/.gitignore
index 47be421..4df4f33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@
 /tests/videogen
 /tests/vsynth1/
 /tools/aviocat
+/tools/device_capabilities
 /tools/ffbisect
 /tools/bisect.need
 /tools/crypto_bench
diff --git a/Makefile b/Makefile
index 5437c0b..bcb6205 100644
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,7 @@ OBJS-ffmpeg                   += ffmpeg_opt.o ffmpeg_filter.o
 OBJS-ffmpeg-$(HAVE_VDPAU_X11) += ffmpeg_vdpau.o
 TESTTOOLS   = audiogen videogen rotozoom tiny_psnr tiny_ssim base64
 HOSTPROGS  := $(TESTTOOLS:%=tests/%) doc/print_options
-TOOLS       = qt-faststart trasher uncoded_frame
+TOOLS       = qt-faststart trasher uncoded_frame device_capabilities
 TOOLS-$(CONFIG_ZLIB) += cws2fws
 
 FFLIBS-$(CONFIG_AVDEVICE) += avdevice
@@ -63,6 +63,8 @@ $(TOOLS): %$(EXESUF): %.o $(EXEOBJS)
 tools/cws2fws$(EXESUF): ELIBS = $(ZLIB)
 tools/uncoded_frame$(EXESUF): $(FF_DEP_LIBS)
 tools/uncoded_frame$(EXESUF): ELIBS = $(FF_EXTRALIBS)
+tools/device_capabilities$(EXESUF): $(FF_DEP_LIBS)
+tools/device_capabilities$(EXESUF): ELIBS = $(FF_EXTRALIBS)
 
 config.h: .config
 .config: $(wildcard $(FFLIBS:%=$(SRC_PATH)/lib%/all*.c))
diff --git a/tools/device_capabilities.c b/tools/device_capabilities.c
new file mode 100644
index 0000000..8320a9c
--- /dev/null
+++ b/tools/device_capabilities.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2014 Lukasz Marek
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libavutil/log.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/avassert.h"
+#include "libavdevice/avdevice.h"
+#include "libavformat/avformat.h"
+
+static void print_available_devices(void)
+{
+    AVInputFormat *i = NULL;
+    AVOutputFormat *o = NULL;
+
+    av_log(NULL, AV_LOG_INFO, "Available devices:\n");
+    av_log(NULL, AV_LOG_INFO, "  input audio:\n");
+    while (i = av_input_audio_device_next(i))
+        av_log(NULL, AV_LOG_INFO, "    %s (%s)\n", i->name, (const char *)av_x_if_null(i->long_name, ""));
+    i = NULL;
+    av_log(NULL, AV_LOG_INFO, "  input video:\n");
+    while (i = av_input_video_device_next(i))
+        av_log(NULL, AV_LOG_INFO, "    %s (%s)\n", i->name, (const char *)av_x_if_null(i->long_name, ""));
+    av_log(NULL, AV_LOG_INFO, "  output audio:\n");
+    while (o = av_output_audio_device_next(o))
+        av_log(NULL, AV_LOG_INFO, "    %s (%s)\n", o->name, (const char *)av_x_if_null(o->long_name, ""));
+    o = NULL;
+    av_log(NULL, AV_LOG_INFO, "  output video:\n");
+    while (o = av_output_video_device_next(o))
+        av_log(NULL, AV_LOG_INFO, "    %s (%s)\n", o->name, (const char *)av_x_if_null(o->long_name, ""));
+}
+
+static int read_number(void)
+{
+    int val = 0;
+    if (scanf("%d", &val) < 1)
+        return 0;
+    return val;
+}
+
+static int print_ranges(AVDeviceCapabilitiesQuery *query, const char *cap_name)
+{
+    int i;
+    AVOptionRanges *ranges;
+    AVOptionRange *range;
+
+    if ((i = av_opt_query_ranges(&ranges, query, cap_name, 0)) < 0) {
+        av_log(query, AV_LOG_ERROR, "Cannot query range of %s\n", cap_name);
+        return i;
+    }
+    av_log(NULL, AV_LOG_INFO, "%-14s: ", cap_name);
+    for (i = 0; i < ranges->nb_ranges; i++) {
+        range = ranges->range[i];
+        if (i)
+            av_log(NULL, AV_LOG_INFO, ", ");
+        if (range->is_range) {
+            if (!strcmp(cap_name, "fps")) {
+                av_log(NULL, AV_LOG_INFO, "%.3f - %.3f", range->value_min[0], range->value_max[0]);
+            } else if (!strcmp(cap_name, "window_size") || !strcmp(cap_name, "frame_size")) {
+                av_log(NULL, AV_LOG_INFO, "%dx%d - %dx%d", (int)range->value_min[0], (int)range->value_min[1],
+                                                            (int)range->value_max[0], (int)range->value_max[1]);
+            } else {
+                av_log(NULL, AV_LOG_INFO, "%d - %d", (int)range->value_min[0], (int)range->value_max[0]);
+            }
+        } else {
+            if (!strcmp(cap_name, "fps")) {
+                av_log(NULL, AV_LOG_INFO, "%.3f", range->value_min[0]);
+            } else if (!strcmp(cap_name, "window_size") || !strcmp(cap_name, "frame_size")) {
+                av_log(NULL, AV_LOG_INFO, "%dx%d", (int)range->value_min[0], (int)range->value_min[1]);
+            } else if (!strcmp(cap_name, "format")) {
+                av_log(NULL, AV_LOG_INFO, "%s", av_get_pix_fmt_name((int)range->value_min[0]));
+            } else if (!strcmp(cap_name, "codec")) {
+                av_log(NULL, AV_LOG_INFO, "%s", avcodec_get_name((int)range->value_min[0]));
+            } else {
+                av_log(NULL, AV_LOG_INFO, "%d", (int)range->value_min[0]);
+            }
+        }
+    }
+    av_log(NULL, AV_LOG_INFO, "\n");
+    av_opt_freep_ranges(&ranges);
+    return 0;
+}
+
+static const AVOption *get_opt(AVFormatContext *oc, AVDeviceCapabilitiesQuery *query,
+                               const AVOption *opt)
+{
+    AVClassCategory c = AV_CLASS_CATEGORY_NA;
+
+    if (oc->iformat)
+        c = oc->iformat->priv_class->category;
+    else if (oc->oformat)
+        c = oc->oformat->priv_class->category;
+    else
+        av_assert0(0);
+
+    while (opt = av_opt_next(query, opt)) {
+        if (!strcmp(opt->name, "device_name"))
+            continue;
+        if (!(opt->flags & AV_OPT_FLAG_AUDIO_PARAM) &&
+            (c == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ||
+             c == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT))
+            continue;
+        if (!(opt->flags & AV_OPT_FLAG_VIDEO_PARAM) &&
+            (c == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ||
+             c == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT))
+            continue;
+        if (!(opt->flags & AV_OPT_FLAG_ENCODING_PARAM) &&
+            (c == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ||
+             c == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ||
+             c == AV_CLASS_CATEGORY_DEVICE_AUDIO_VIDEO_OUTPUT))
+            continue;
+        if (!(opt->flags & AV_OPT_FLAG_DECODING_PARAM) &&
+            (c == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ||
+             c == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ||
+             c == AV_CLASS_CATEGORY_DEVICE_AUDIO_VIDEO_INPUT))
+            continue;
+        break;
+    }
+    return opt;
+}
+
+static int print_all(AVFormatContext *oc, AVDeviceCapabilitiesQuery *query)
+{
+    const AVOption *opt = NULL;
+    int cnt = 0;
+    av_log(NULL, AV_LOG_INFO, "\n");
+    av_log(NULL, AV_LOG_INFO, "Current option ranges for the device are:\n");
+    while (opt = get_opt(oc, query, opt)) {
+        print_ranges(query, opt->name);
+        cnt++;
+    }
+    return cnt;
+}
+
+static void list_options(AVFormatContext *oc, AVDeviceCapabilitiesQuery *query)
+{
+    const AVOption *opt = NULL;
+    av_log(NULL, AV_LOG_INFO, "\n");
+    av_log(NULL, AV_LOG_INFO, "Available options for the device are:\n");
+    while (opt = get_opt(oc, query, opt))
+        av_log(NULL, AV_LOG_INFO, "%s\n", opt->name);
+}
+
+static int select_device(AVFormatContext *oc, AVDeviceCapabilitiesQuery *query)
+{
+    int i, ret;
+    AVDeviceInfoList *devices = NULL;
+
+    if ((ret = avdevice_list_devices(oc, &devices)) < 0)
+        goto fail;
+    if (!devices->nb_devices) {
+        av_log(oc, AV_LOG_WARNING, "No devices found");
+        ret = -1;
+        goto fail;
+    }
+    av_log(NULL, AV_LOG_INFO, "Autodetected devices:\n");
+    for (i = 0; i < devices->nb_devices; i++) {
+        av_log(NULL, AV_LOG_INFO, "#%d: %s %s %s.\n", i + 1,
+               devices->default_device == i ? "*" : " ",
+               devices->devices[i]->device_description,
+               devices->devices[i]->device_name);
+    }
+
+    do {
+        av_log(NULL, AV_LOG_INFO, "Select device: ");
+        ret = read_number();
+    } while (ret > devices->nb_devices);
+    if (ret <= 0) {
+        ret = -1;
+        goto fail;
+    }
+
+    av_opt_set(query, "device_name", devices->devices[ret - 1]->device_name, 0);
+    av_log(NULL, AV_LOG_INFO, "Selected device: %s\n",
+           devices->devices[ret - 1]->device_description);
+
+    ret = 0;
+  fail:
+    avdevice_free_list_devices(&devices);
+    return ret;
+}
+
+static int set_codec(AVDeviceCapabilitiesQuery *query)
+{
+    AVCodec *codec;
+    char str[100];
+    av_log(NULL, AV_LOG_INFO, "Enter codec name: ");
+    scanf("%99s", str);
+    codec = avcodec_find_encoder_by_name(str);
+    if (!codec)
+        codec = avcodec_find_decoder_by_name(str);
+    if (!codec)
+        return AVERROR(EINVAL);
+    return av_opt_set_int(query, "codec", codec->id, 0);
+}
+
+static int set_pixel_format(AVDeviceCapabilitiesQuery *query)
+{
+    enum AVPixelFormat fmt;
+    char str[100];
+    av_log(NULL, AV_LOG_INFO, "Enter pixel format name: ");
+    if (scanf("%99s", str) < 1)
+        return -1;
+    fmt = av_get_pix_fmt(str);
+    if (fmt == AV_PIX_FMT_NONE)
+        return AVERROR(EINVAL);
+    return av_opt_set_int(query, "format", fmt, 0);
+}
+
+static int set_size(AVDeviceCapabilitiesQuery *query, const char *cap)
+{
+    char str[100];
+    av_log(NULL, AV_LOG_INFO, "Enter new size: ");
+    if (scanf("%99s", str) < 1)
+        return -1;
+    return av_opt_set(query, cap, str, 0);
+}
+
+static int set_double(AVDeviceCapabilitiesQuery *query, const char *cap)
+{
+    double d;
+    av_log(NULL, AV_LOG_INFO, "Enter new value: ");
+    if (scanf("%lf", &d) < 1)
+        return -1;
+    return av_opt_set_double(query, cap, d, 0);
+}
+
+static int set_option(AVFormatContext *oc, AVDeviceCapabilitiesQuery *query)
+{
+    int ret;
+    char buf[100];
+
+    print_all(oc, query);
+    do {
+        av_log(NULL, AV_LOG_INFO, "Select option to set (q for quit, r for reset): ");
+        scanf("%99s", buf);
+        ret = 0;
+        if (!strcmp(buf, "format"))
+            ret = set_pixel_format(query);
+        else if (!strcmp(buf, "codec"))
+            ret = set_codec(query);
+        else if (!strcmp(buf, "window_size") || !strcmp(buf, "frame_size"))
+            ret = set_size(query, buf);
+        else if (!strcmp(buf, "fps"))
+            ret = set_double(query, buf);
+        else if (!strcmp(buf, "r"))
+            av_opt_set_defaults(query);
+        else
+            av_log(NULL, AV_LOG_ERROR, "Invalid option.\n");
+        if (ret < 0)
+            av_log(NULL, AV_LOG_ERROR, "Option not set.\n");
+        else
+            print_all(oc, query);
+    } while (strcmp(buf, "q"));
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    AVFormatContext *oc = NULL;
+    AVDeviceCapabilitiesQuery *query = NULL;
+    const char *dev_name;
+    int ret;
+
+    av_register_all();
+    avdevice_register_all();
+
+    if (argc < 2) {
+        av_log(NULL, AV_LOG_INFO, "Usage: %s device_name\n", argv[0]);
+        print_available_devices();
+        exit(1);
+    }
+    dev_name = argv[1];
+
+    ret = avformat_alloc_output_context2(&oc, NULL, dev_name, NULL);
+    if (ret < 0) {
+        av_log(NULL, AV_LOG_ERROR, "Could not allocate output format context for %s.\n", dev_name);
+        goto fail;
+    }
+
+    if ((ret = avdevice_capabilities_create(&query, oc, NULL)) < 0) {
+        av_log(NULL, AV_LOG_ERROR, "Could not allocate device capabilities query data.\n");
+        goto fail;
+    }
+
+    if ((ret = select_device(oc, query)) < 0)
+        goto fail;
+
+    list_options(oc, query);
+    set_option(oc, query);
+
+    ret = 0;
+  fail:
+    if (ret < 0)
+        ret = 1;
+    avdevice_capabilities_free(&query, oc);
+    avformat_free_context(oc);
+    return ret;
+}
-- 
1.8.3.2



More information about the ffmpeg-devel mailing list