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

Xiang, Haihao haihao.xiang at intel.com
Tue May 15 05:16:11 EEST 2018


On Mon, 2018-05-14 at 22:58 +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.
> ---
>  libavutil/Makefile         |   1 +
>  libavutil/tests/hwdevice.c | 234
> +++++++++++++++++++++++++++++++++++++++++++++
>  tests/fate/libavutil.mak   |   4 +
>  tests/ref/fate/hwdevice    |   1 +
>  4 files changed, 240 insertions(+)
>  create mode 100644 libavutil/tests/hwdevice.c
>  create mode 100644 tests/ref/fate/hwdevice
> 
> 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/hwdevice.c b/libavutil/tests/hwdevice.c
> new file mode 100644
> index 0000000000..a14c4be8a4
> --- /dev/null
> +++ b/libavutil/tests/hwdevice.c
> @@ -0,0 +1,234 @@
> +/*
> + * 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, *back_ref;
> +    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) {
> +            printf("Device derived as type %d has type %d.\n",
> +                   derived_type, derived_dev->type);

back_ref might not be initialized in the error handling path,

> +            goto fail;
> +        }
> +
> +        if (derived_type == src_dev->type) {
> +            if (derived_dev != src_dev) {
> +                printf("Derivation of %s from itself succeeded but did "
> +                       "not return the same device.\n", src_name);

Same as above. 

> +                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) {
> +            printf("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) {
> +            printf("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) {
> +        printf("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) {
> +        printf("No name available for device type %d.\n", type);
> +        return -1;
> +    }
> +
> +    check = av_hwdevice_find_type_by_name(name);
> +    if (check != type) {
> +        printf("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) {
> +        printf("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) {
> +                printf("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);
> +
> +    if (fail > 0) {
> +        printf("Failed (%d passed, %d failed, %d skipped).\n",
> +               pass, fail, skip);
> +        return 1;
> +    } else {
> +        // This can't contain any more detail because the output would
> +        // differ depending on system and configure options.
> +        printf("Passed.\n");
> +        return 0;
> +    }

Is it possible to use the same stream for error message? Both printf() and
fprintf(stderr) are used for error message in the patch. In addition, it would
be better to use stdout for non-error message. 

> +}
> diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak
> index 9b32d880f5..f5e0cfdd1b 100644
> --- a/tests/fate/libavutil.mak
> +++ b/tests/fate/libavutil.mak
> @@ -86,6 +86,10 @@ FATE_LIBAVUTIL += fate-hmac
>  fate-hmac: libavutil/tests/hmac$(EXESUF)
>  fate-hmac: CMD = run libavutil/tests/hmac
>  
> +FATE_LIBAVUTIL += fate-hwdevice
> +fate-hwdevice: libavutil/tests/hwdevice$(EXESUF)
> +fate-hwdevice: CMD = run libavutil/tests/hwdevice
> +
>  FATE_LIBAVUTIL += fate-imgutils
>  fate-imgutils: libavutil/tests/imgutils$(EXESUF)
>  fate-imgutils: CMD = run libavutil/tests/imgutils
> diff --git a/tests/ref/fate/hwdevice b/tests/ref/fate/hwdevice
> new file mode 100644
> index 0000000000..02876925f0
> --- /dev/null
> +++ b/tests/ref/fate/hwdevice
> @@ -0,0 +1 @@
> +Passed.


More information about the ffmpeg-devel mailing list