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

Xiang, Haihao haihao.xiang at intel.com
Wed May 16 04:14:11 EEST 2018


On Tue, 2018-05-15 at 23:15 +0100, Mark Thompson wrote:
> 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)

LGTM, thanks


More information about the ffmpeg-devel mailing list