1/* 2 * This file is part of FFmpeg. 3 * 4 * FFmpeg is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * FFmpeg is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with FFmpeg; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include <stdio.h> 20 21#include "libavutil/hwcontext.h" 22 23static int test_derivation(AVBufferRef *src_ref, const char *src_name) 24{ 25 enum AVHWDeviceType derived_type; 26 const char *derived_name; 27 AVBufferRef *derived_ref = NULL, *back_ref = NULL; 28 AVHWDeviceContext *src_dev, *derived_dev; 29 int err; 30 31 src_dev = (AVHWDeviceContext*)src_ref->data; 32 33 derived_type = AV_HWDEVICE_TYPE_NONE; 34 while (1) { 35 derived_type = av_hwdevice_iterate_types(derived_type); 36 if (derived_type == AV_HWDEVICE_TYPE_NONE) 37 break; 38 39 derived_name = av_hwdevice_get_type_name(derived_type); 40 41 err = av_hwdevice_ctx_create_derived(&derived_ref, derived_type, 42 src_ref, 0); 43 if (err < 0) { 44 fprintf(stderr, "Unable to derive %s -> %s: %d.\n", 45 src_name, derived_name, err); 46 continue; 47 } 48 49 derived_dev = (AVHWDeviceContext*)derived_ref->data; 50 if (derived_dev->type != derived_type) { 51 fprintf(stderr, "Device derived as type %d has type %d.\n", 52 derived_type, derived_dev->type); 53 goto fail; 54 } 55 56 if (derived_type == src_dev->type) { 57 if (derived_dev != src_dev) { 58 fprintf(stderr, "Derivation of %s from itself succeeded " 59 "but did not return the same device.\n", src_name); 60 goto fail; 61 } 62 av_buffer_unref(&derived_ref); 63 continue; 64 } 65 66 err = av_hwdevice_ctx_create_derived(&back_ref, src_dev->type, 67 derived_ref, 0); 68 if (err < 0) { 69 fprintf(stderr, "Derivation %s to %s succeeded, but derivation " 70 "back again failed: %d.\n", 71 src_name, derived_name, err); 72 goto fail; 73 } 74 75 if (back_ref->data != src_ref->data) { 76 fprintf(stderr, "Derivation %s to %s succeeded, but derivation " 77 "back again did not return the original device.\n", 78 src_name, derived_name); 79 goto fail; 80 } 81 82 fprintf(stderr, "Successfully tested derivation %s -> %s.\n", 83 src_name, derived_name); 84 85 av_buffer_unref(&derived_ref); 86 av_buffer_unref(&back_ref); 87 } 88 89 return 0; 90 91fail: 92 av_buffer_unref(&derived_ref); 93 av_buffer_unref(&back_ref); 94 return -1; 95} 96 97static int test_device(enum AVHWDeviceType type, const char *name, 98 const char *device, AVDictionary *opts, int flags) 99{ 100 AVBufferRef *ref; 101 AVHWDeviceContext *dev; 102 int err; 103 104 err = av_hwdevice_ctx_create(&ref, type, device, opts, flags); 105 if (err < 0) { 106 fprintf(stderr, "Failed to create %s device: %d.\n", name, err); 107 return 1; 108 } 109 110 dev = (AVHWDeviceContext*)ref->data; 111 if (dev->type != type) { 112 fprintf(stderr, "Device created as type %d has type %d.\n", 113 type, dev->type); 114 av_buffer_unref(&ref); 115 return -1; 116 } 117 118 fprintf(stderr, "Device type %s successfully created.\n", name); 119 120 err = test_derivation(ref, name); 121 122 av_buffer_unref(&ref); 123 124 return err; 125} 126 127static const struct { 128 enum AVHWDeviceType type; 129 const char *possible_devices[5]; 130} test_devices[] = { 131 { AV_HWDEVICE_TYPE_CUDA, 132 { "0", "1", "2" } }, 133 { AV_HWDEVICE_TYPE_DRM, 134 { "/dev/dri/card0", "/dev/dri/card1", 135 "/dev/dri/renderD128", "/dev/dri/renderD129" } }, 136 { AV_HWDEVICE_TYPE_DXVA2, 137 { "0", "1", "2" } }, 138 { AV_HWDEVICE_TYPE_D3D11VA, 139 { "0", "1", "2" } }, 140 { AV_HWDEVICE_TYPE_OPENCL, 141 { "0.0", "0.1", "1.0", "1.1" } }, 142 { AV_HWDEVICE_TYPE_VAAPI, 143 { "/dev/dri/renderD128", "/dev/dri/renderD129", ":0" } }, 144}; 145 146static int test_device_type(enum AVHWDeviceType type) 147{ 148 enum AVHWDeviceType check; 149 const char *name; 150 int i, j, found, err; 151 152 name = av_hwdevice_get_type_name(type); 153 if (!name) { 154 fprintf(stderr, "No name available for device type %d.\n", type); 155 return -1; 156 } 157 158 check = av_hwdevice_find_type_by_name(name); 159 if (check != type) { 160 fprintf(stderr, "Type %d maps to name %s maps to type %d.\n", 161 type, name, check); 162 return -1; 163 } 164 165 found = 0; 166 167 err = test_device(type, name, NULL, NULL, 0); 168 if (err < 0) { 169 fprintf(stderr, "Test failed for %s with default options.\n", name); 170 return -1; 171 } 172 if (err == 0) { 173 fprintf(stderr, "Test passed for %s with default options.\n", name); 174 ++found; 175 } 176 177 for (i = 0; i < FF_ARRAY_ELEMS(test_devices); i++) { 178 if (test_devices[i].type != type) 179 continue; 180 181 for (j = 0; test_devices[i].possible_devices[j]; j++) { 182 err = test_device(type, name, 183 test_devices[i].possible_devices[j], 184 NULL, 0); 185 if (err < 0) { 186 fprintf(stderr, "Test failed for %s with device %s.\n", 187 name, test_devices[i].possible_devices[j]); 188 return -1; 189 } 190 if (err == 0) { 191 fprintf(stderr, "Test passed for %s with device %s.\n", 192 name, test_devices[i].possible_devices[j]); 193 ++found; 194 } 195 } 196 } 197 198 return !found; 199} 200 201int main(void) 202{ 203 enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; 204 int pass, fail, skip, err; 205 206 pass = fail = skip = 0; 207 while (1) { 208 type = av_hwdevice_iterate_types(type); 209 if (type == AV_HWDEVICE_TYPE_NONE) 210 break; 211 212 err = test_device_type(type); 213 if (err == 0) 214 ++pass; 215 else if (err < 0) 216 ++fail; 217 else 218 ++skip; 219 } 220 221 fprintf(stderr, "Attempted to test %d device types: " 222 "%d passed, %d failed, %d skipped.\n", 223 pass + fail + skip, pass, fail, skip); 224 225 return fail > 0; 226} 227