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

Mark Thompson sw at jkqxz.net
Tue May 22 00:48:45 EEST 2018


On 16/05/18 02:14, Xiang, Haihao wrote:
> 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

Applied.

Thanks,

- Mark


More information about the ffmpeg-devel mailing list