[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