From ba7d1377e85662f7b4ae728719c10d5427cc6b9b Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Tue, 15 May 2018 23:15:03 +0100 Subject: [PATCH] hwcontext: Add test for device creation and derivation This uses any devices it can find on the host system - on a system with no hardware device support or in builds with no support included it will do nothing and pass. --- libavutil/Makefile | 1 + libavutil/tests/.gitignore | 1 + libavutil/tests/hwdevice.c | 226 +++++++++++++++++++++++++++++++++++++ tests/Makefile | 5 + tests/fate/hw.mak | 6 + 5 files changed, 239 insertions(+) create mode 100644 libavutil/tests/hwdevice.c create mode 100644 tests/fate/hw.mak diff --git a/libavutil/Makefile b/libavutil/Makefile index 4fe470748c..d0632f16a6 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -206,6 +206,7 @@ TESTPROGS = adler32 \ fifo \ hash \ hmac \ + hwdevice \ integer \ imgutils \ lfg \ diff --git a/libavutil/tests/.gitignore b/libavutil/tests/.gitignore index 8ede070887..71f75a8ee9 100644 --- a/libavutil/tests/.gitignore +++ b/libavutil/tests/.gitignore @@ -22,6 +22,7 @@ /file /hash /hmac +/hwdevice /imgutils /lfg /lls diff --git a/libavutil/tests/hwdevice.c b/libavutil/tests/hwdevice.c new file mode 100644 index 0000000000..7eb355c988 --- /dev/null +++ b/libavutil/tests/hwdevice.c @@ -0,0 +1,226 @@ +/* + * 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 + +#include "libavutil/hwcontext.h" + +static int test_derivation(AVBufferRef *src_ref, const char *src_name) +{ + enum AVHWDeviceType derived_type; + const char *derived_name; + AVBufferRef *derived_ref = NULL, *back_ref = NULL; + AVHWDeviceContext *src_dev, *derived_dev; + int err; + + src_dev = (AVHWDeviceContext*)src_ref->data; + + derived_type = AV_HWDEVICE_TYPE_NONE; + while (1) { + derived_type = av_hwdevice_iterate_types(derived_type); + if (derived_type == AV_HWDEVICE_TYPE_NONE) + break; + + derived_name = av_hwdevice_get_type_name(derived_type); + + err = av_hwdevice_ctx_create_derived(&derived_ref, derived_type, + src_ref, 0); + if (err < 0) { + fprintf(stderr, "Unable to derive %s -> %s: %d.\n", + src_name, derived_name, err); + continue; + } + + derived_dev = (AVHWDeviceContext*)derived_ref->data; + if (derived_dev->type != derived_type) { + fprintf(stderr, "Device derived as type %d has type %d.\n", + derived_type, derived_dev->type); + goto fail; + } + + if (derived_type == src_dev->type) { + if (derived_dev != src_dev) { + fprintf(stderr, "Derivation of %s from itself succeeded " + "but did not return the same device.\n", src_name); + goto fail; + } + av_buffer_unref(&derived_ref); + continue; + } + + err = av_hwdevice_ctx_create_derived(&back_ref, src_dev->type, + derived_ref, 0); + if (err < 0) { + fprintf(stderr, "Derivation %s to %s succeeded, but derivation " + "back again failed: %d.\n", + src_name, derived_name, err); + goto fail; + } + + if (back_ref->data != src_ref->data) { + fprintf(stderr, "Derivation %s to %s succeeded, but derivation " + "back again did not return the original device.\n", + src_name, derived_name); + goto fail; + } + + fprintf(stderr, "Successfully tested derivation %s -> %s.\n", + src_name, derived_name); + + av_buffer_unref(&derived_ref); + av_buffer_unref(&back_ref); + } + + return 0; + +fail: + av_buffer_unref(&derived_ref); + av_buffer_unref(&back_ref); + return -1; +} + +static int test_device(enum AVHWDeviceType type, const char *name, + const char *device, AVDictionary *opts, int flags) +{ + AVBufferRef *ref; + AVHWDeviceContext *dev; + int err; + + err = av_hwdevice_ctx_create(&ref, type, device, opts, flags); + if (err < 0) { + fprintf(stderr, "Failed to create %s device: %d.\n", name, err); + return 1; + } + + dev = (AVHWDeviceContext*)ref->data; + if (dev->type != type) { + fprintf(stderr, "Device created as type %d has type %d.\n", + type, dev->type); + av_buffer_unref(&ref); + return -1; + } + + fprintf(stderr, "Device type %s successfully created.\n", name); + + err = test_derivation(ref, name); + + av_buffer_unref(&ref); + + return err; +} + +static const struct { + enum AVHWDeviceType type; + const char *possible_devices[5]; +} test_devices[] = { + { AV_HWDEVICE_TYPE_CUDA, + { "0", "1", "2" } }, + { AV_HWDEVICE_TYPE_DRM, + { "/dev/dri/card0", "/dev/dri/card1", + "/dev/dri/renderD128", "/dev/dri/renderD129" } }, + { AV_HWDEVICE_TYPE_DXVA2, + { "0", "1", "2" } }, + { AV_HWDEVICE_TYPE_D3D11VA, + { "0", "1", "2" } }, + { AV_HWDEVICE_TYPE_OPENCL, + { "0.0", "0.1", "1.0", "1.1" } }, + { AV_HWDEVICE_TYPE_VAAPI, + { "/dev/dri/renderD128", "/dev/dri/renderD129", ":0" } }, +}; + +static int test_device_type(enum AVHWDeviceType type) +{ + enum AVHWDeviceType check; + const char *name; + int i, j, found, err; + + name = av_hwdevice_get_type_name(type); + if (!name) { + fprintf(stderr, "No name available for device type %d.\n", type); + return -1; + } + + check = av_hwdevice_find_type_by_name(name); + if (check != type) { + fprintf(stderr, "Type %d maps to name %s maps to type %d.\n", + type, name, check); + return -1; + } + + found = 0; + + err = test_device(type, name, NULL, NULL, 0); + if (err < 0) { + fprintf(stderr, "Test failed for %s with default options.\n", name); + return -1; + } + if (err == 0) { + fprintf(stderr, "Test passed for %s with default options.\n", name); + ++found; + } + + for (i = 0; i < FF_ARRAY_ELEMS(test_devices); i++) { + if (test_devices[i].type != type) + continue; + + for (j = 0; test_devices[i].possible_devices[j]; j++) { + err = test_device(type, name, + test_devices[i].possible_devices[j], + NULL, 0); + if (err < 0) { + fprintf(stderr, "Test failed for %s with device %s.\n", + name, test_devices[i].possible_devices[j]); + return -1; + } + if (err == 0) { + fprintf(stderr, "Test passed for %s with device %s.\n", + name, test_devices[i].possible_devices[j]); + ++found; + } + } + } + + return !found; +} + +int main(void) +{ + enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; + int pass, fail, skip, err; + + pass = fail = skip = 0; + while (1) { + type = av_hwdevice_iterate_types(type); + if (type == AV_HWDEVICE_TYPE_NONE) + break; + + err = test_device_type(type); + if (err == 0) + ++pass; + else if (err < 0) + ++fail; + else + ++skip; + } + + fprintf(stderr, "Attempted to test %d device types: " + "%d passed, %d failed, %d skipped.\n", + pass + fail + skip, pass, fail, skip); + + return fail > 0; +} diff --git a/tests/Makefile b/tests/Makefile index 6074ac748e..98d7b6d608 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -131,6 +131,7 @@ include $(SRC_PATH)/tests/fate/gif.mak include $(SRC_PATH)/tests/fate/h264.mak include $(SRC_PATH)/tests/fate/hap.mak include $(SRC_PATH)/tests/fate/hevc.mak +include $(SRC_PATH)/tests/fate/hw.mak include $(SRC_PATH)/tests/fate/id3v2.mak include $(SRC_PATH)/tests/fate/image.mak include $(SRC_PATH)/tests/fate/indeo.mak @@ -215,6 +216,10 @@ $(addprefix fate-, $(IGNORE_TESTS)): REPORT=ignore fate:: $(FATE) +# Tests requiring hardware support are not included in a default fate run. +fate-hw: $(FATE_HW-yes) +FATE += $(FATE_HW-yes) + $(FATE) $(FATE_TESTS-no): export PROGSUF = $(PROGSSUF) $(FATE) $(FATE_TESTS-no): $(FATE_UTILS:%=tests/%$(HOSTEXESUF)) @echo "TEST $(@:fate-%=%)" diff --git a/tests/fate/hw.mak b/tests/fate/hw.mak new file mode 100644 index 0000000000..d606cdeab6 --- /dev/null +++ b/tests/fate/hw.mak @@ -0,0 +1,6 @@ +FATE_HWCONTEXT += fate-hwdevice +fate-hwdevice: libavutil/tests/hwdevice$(EXESUF) +fate-hwdevice: CMD = run libavutil/tests/hwdevice +fate-hwdevice: CMP = null + +FATE_HW-$(CONFIG_AVUTIL) += $(FATE_HWCONTEXT)