[FFmpeg-devel] [PATCH v2] hwcontext: Add test for device creation and derivation

Mark Thompson sw at jkqxz.net
Wed May 16 01:15:03 EEST 2018


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.
---

It now comes under a new target "fate-hw", which is not run as part of "fate".

I found the CMP option, so it no longer has a reference file.  All output is therefore now on stderr.

Thanks,

- Mark

(In terms of further tests under fate-hw, I'm intending to add a hwframes test which tries to make frames contexts and do upload/download.  There should probably be something with frames context mapping too, but I'm unsure exactly what.  I'd also like to have some tests for the complex header construction code in VAAPI encode, but how to actually run that needs a bit more thought.)


 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 <stdio.h>
+
+#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)
-- 
2.16.3



More information about the ffmpeg-devel mailing list