1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * This file is part of FFmpeg. 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cabdff1aSopenharmony_ci * Lesser General Public License for more details. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17cabdff1aSopenharmony_ci */ 18cabdff1aSopenharmony_ci 19cabdff1aSopenharmony_ci#include <string.h> 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 22cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h" 23cabdff1aSopenharmony_ci#include "libavfilter/buffersink.h" 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "ffmpeg.h" 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_cistatic int nb_hw_devices; 28cabdff1aSopenharmony_cistatic HWDevice **hw_devices; 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_cistatic HWDevice *hw_device_get_by_type(enum AVHWDeviceType type) 31cabdff1aSopenharmony_ci{ 32cabdff1aSopenharmony_ci HWDevice *found = NULL; 33cabdff1aSopenharmony_ci int i; 34cabdff1aSopenharmony_ci for (i = 0; i < nb_hw_devices; i++) { 35cabdff1aSopenharmony_ci if (hw_devices[i]->type == type) { 36cabdff1aSopenharmony_ci if (found) 37cabdff1aSopenharmony_ci return NULL; 38cabdff1aSopenharmony_ci found = hw_devices[i]; 39cabdff1aSopenharmony_ci } 40cabdff1aSopenharmony_ci } 41cabdff1aSopenharmony_ci return found; 42cabdff1aSopenharmony_ci} 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_ciHWDevice *hw_device_get_by_name(const char *name) 45cabdff1aSopenharmony_ci{ 46cabdff1aSopenharmony_ci int i; 47cabdff1aSopenharmony_ci for (i = 0; i < nb_hw_devices; i++) { 48cabdff1aSopenharmony_ci if (!strcmp(hw_devices[i]->name, name)) 49cabdff1aSopenharmony_ci return hw_devices[i]; 50cabdff1aSopenharmony_ci } 51cabdff1aSopenharmony_ci return NULL; 52cabdff1aSopenharmony_ci} 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_cistatic HWDevice *hw_device_add(void) 55cabdff1aSopenharmony_ci{ 56cabdff1aSopenharmony_ci int err; 57cabdff1aSopenharmony_ci err = av_reallocp_array(&hw_devices, nb_hw_devices + 1, 58cabdff1aSopenharmony_ci sizeof(*hw_devices)); 59cabdff1aSopenharmony_ci if (err) { 60cabdff1aSopenharmony_ci nb_hw_devices = 0; 61cabdff1aSopenharmony_ci return NULL; 62cabdff1aSopenharmony_ci } 63cabdff1aSopenharmony_ci hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice)); 64cabdff1aSopenharmony_ci if (!hw_devices[nb_hw_devices]) 65cabdff1aSopenharmony_ci return NULL; 66cabdff1aSopenharmony_ci return hw_devices[nb_hw_devices++]; 67cabdff1aSopenharmony_ci} 68cabdff1aSopenharmony_ci 69cabdff1aSopenharmony_cistatic char *hw_device_default_name(enum AVHWDeviceType type) 70cabdff1aSopenharmony_ci{ 71cabdff1aSopenharmony_ci // Make an automatic name of the form "type%d". We arbitrarily 72cabdff1aSopenharmony_ci // limit at 1000 anonymous devices of the same type - there is 73cabdff1aSopenharmony_ci // probably something else very wrong if you get to this limit. 74cabdff1aSopenharmony_ci const char *type_name = av_hwdevice_get_type_name(type); 75cabdff1aSopenharmony_ci char *name; 76cabdff1aSopenharmony_ci size_t index_pos; 77cabdff1aSopenharmony_ci int index, index_limit = 1000; 78cabdff1aSopenharmony_ci index_pos = strlen(type_name); 79cabdff1aSopenharmony_ci name = av_malloc(index_pos + 4); 80cabdff1aSopenharmony_ci if (!name) 81cabdff1aSopenharmony_ci return NULL; 82cabdff1aSopenharmony_ci for (index = 0; index < index_limit; index++) { 83cabdff1aSopenharmony_ci snprintf(name, index_pos + 4, "%s%d", type_name, index); 84cabdff1aSopenharmony_ci if (!hw_device_get_by_name(name)) 85cabdff1aSopenharmony_ci break; 86cabdff1aSopenharmony_ci } 87cabdff1aSopenharmony_ci if (index >= index_limit) { 88cabdff1aSopenharmony_ci av_freep(&name); 89cabdff1aSopenharmony_ci return NULL; 90cabdff1aSopenharmony_ci } 91cabdff1aSopenharmony_ci return name; 92cabdff1aSopenharmony_ci} 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_ciint hw_device_init_from_string(const char *arg, HWDevice **dev_out) 95cabdff1aSopenharmony_ci{ 96cabdff1aSopenharmony_ci // "type=name" 97cabdff1aSopenharmony_ci // "type=name,key=value,key2=value2" 98cabdff1aSopenharmony_ci // "type=name:device,key=value,key2=value2" 99cabdff1aSopenharmony_ci // "type:device,key=value,key2=value2" 100cabdff1aSopenharmony_ci // -> av_hwdevice_ctx_create() 101cabdff1aSopenharmony_ci // "type=name@name" 102cabdff1aSopenharmony_ci // "type@name" 103cabdff1aSopenharmony_ci // -> av_hwdevice_ctx_create_derived() 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci AVDictionary *options = NULL; 106cabdff1aSopenharmony_ci const char *type_name = NULL, *name = NULL, *device = NULL; 107cabdff1aSopenharmony_ci enum AVHWDeviceType type; 108cabdff1aSopenharmony_ci HWDevice *dev, *src; 109cabdff1aSopenharmony_ci AVBufferRef *device_ref = NULL; 110cabdff1aSopenharmony_ci int err; 111cabdff1aSopenharmony_ci const char *errmsg, *p, *q; 112cabdff1aSopenharmony_ci size_t k; 113cabdff1aSopenharmony_ci 114cabdff1aSopenharmony_ci k = strcspn(arg, ":=@"); 115cabdff1aSopenharmony_ci p = arg + k; 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci type_name = av_strndup(arg, k); 118cabdff1aSopenharmony_ci if (!type_name) { 119cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 120cabdff1aSopenharmony_ci goto fail; 121cabdff1aSopenharmony_ci } 122cabdff1aSopenharmony_ci type = av_hwdevice_find_type_by_name(type_name); 123cabdff1aSopenharmony_ci if (type == AV_HWDEVICE_TYPE_NONE) { 124cabdff1aSopenharmony_ci errmsg = "unknown device type"; 125cabdff1aSopenharmony_ci goto invalid; 126cabdff1aSopenharmony_ci } 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci if (*p == '=') { 129cabdff1aSopenharmony_ci k = strcspn(p + 1, ":@,"); 130cabdff1aSopenharmony_ci 131cabdff1aSopenharmony_ci name = av_strndup(p + 1, k); 132cabdff1aSopenharmony_ci if (!name) { 133cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 134cabdff1aSopenharmony_ci goto fail; 135cabdff1aSopenharmony_ci } 136cabdff1aSopenharmony_ci if (hw_device_get_by_name(name)) { 137cabdff1aSopenharmony_ci errmsg = "named device already exists"; 138cabdff1aSopenharmony_ci goto invalid; 139cabdff1aSopenharmony_ci } 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_ci p += 1 + k; 142cabdff1aSopenharmony_ci } else { 143cabdff1aSopenharmony_ci name = hw_device_default_name(type); 144cabdff1aSopenharmony_ci if (!name) { 145cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 146cabdff1aSopenharmony_ci goto fail; 147cabdff1aSopenharmony_ci } 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci if (!*p) { 151cabdff1aSopenharmony_ci // New device with no parameters. 152cabdff1aSopenharmony_ci err = av_hwdevice_ctx_create(&device_ref, type, 153cabdff1aSopenharmony_ci NULL, NULL, 0); 154cabdff1aSopenharmony_ci if (err < 0) 155cabdff1aSopenharmony_ci goto fail; 156cabdff1aSopenharmony_ci 157cabdff1aSopenharmony_ci } else if (*p == ':') { 158cabdff1aSopenharmony_ci // New device with some parameters. 159cabdff1aSopenharmony_ci ++p; 160cabdff1aSopenharmony_ci q = strchr(p, ','); 161cabdff1aSopenharmony_ci if (q) { 162cabdff1aSopenharmony_ci if (q - p > 0) { 163cabdff1aSopenharmony_ci device = av_strndup(p, q - p); 164cabdff1aSopenharmony_ci if (!device) { 165cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 166cabdff1aSopenharmony_ci goto fail; 167cabdff1aSopenharmony_ci } 168cabdff1aSopenharmony_ci } 169cabdff1aSopenharmony_ci err = av_dict_parse_string(&options, q + 1, "=", ",", 0); 170cabdff1aSopenharmony_ci if (err < 0) { 171cabdff1aSopenharmony_ci errmsg = "failed to parse options"; 172cabdff1aSopenharmony_ci goto invalid; 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci } 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci err = av_hwdevice_ctx_create(&device_ref, type, 177cabdff1aSopenharmony_ci q ? device : p[0] ? p : NULL, 178cabdff1aSopenharmony_ci options, 0); 179cabdff1aSopenharmony_ci if (err < 0) 180cabdff1aSopenharmony_ci goto fail; 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci } else if (*p == '@') { 183cabdff1aSopenharmony_ci // Derive from existing device. 184cabdff1aSopenharmony_ci 185cabdff1aSopenharmony_ci src = hw_device_get_by_name(p + 1); 186cabdff1aSopenharmony_ci if (!src) { 187cabdff1aSopenharmony_ci errmsg = "invalid source device name"; 188cabdff1aSopenharmony_ci goto invalid; 189cabdff1aSopenharmony_ci } 190cabdff1aSopenharmony_ci 191cabdff1aSopenharmony_ci err = av_hwdevice_ctx_create_derived(&device_ref, type, 192cabdff1aSopenharmony_ci src->device_ref, 0); 193cabdff1aSopenharmony_ci if (err < 0) 194cabdff1aSopenharmony_ci goto fail; 195cabdff1aSopenharmony_ci } else if (*p == ',') { 196cabdff1aSopenharmony_ci err = av_dict_parse_string(&options, p + 1, "=", ",", 0); 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_ci if (err < 0) { 199cabdff1aSopenharmony_ci errmsg = "failed to parse options"; 200cabdff1aSopenharmony_ci goto invalid; 201cabdff1aSopenharmony_ci } 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci err = av_hwdevice_ctx_create(&device_ref, type, 204cabdff1aSopenharmony_ci NULL, options, 0); 205cabdff1aSopenharmony_ci if (err < 0) 206cabdff1aSopenharmony_ci goto fail; 207cabdff1aSopenharmony_ci } else { 208cabdff1aSopenharmony_ci errmsg = "parse error"; 209cabdff1aSopenharmony_ci goto invalid; 210cabdff1aSopenharmony_ci } 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_ci dev = hw_device_add(); 213cabdff1aSopenharmony_ci if (!dev) { 214cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 215cabdff1aSopenharmony_ci goto fail; 216cabdff1aSopenharmony_ci } 217cabdff1aSopenharmony_ci 218cabdff1aSopenharmony_ci dev->name = name; 219cabdff1aSopenharmony_ci dev->type = type; 220cabdff1aSopenharmony_ci dev->device_ref = device_ref; 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_ci if (dev_out) 223cabdff1aSopenharmony_ci *dev_out = dev; 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci name = NULL; 226cabdff1aSopenharmony_ci err = 0; 227cabdff1aSopenharmony_cidone: 228cabdff1aSopenharmony_ci av_freep(&type_name); 229cabdff1aSopenharmony_ci av_freep(&name); 230cabdff1aSopenharmony_ci av_freep(&device); 231cabdff1aSopenharmony_ci av_dict_free(&options); 232cabdff1aSopenharmony_ci return err; 233cabdff1aSopenharmony_ciinvalid: 234cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, 235cabdff1aSopenharmony_ci "Invalid device specification \"%s\": %s\n", arg, errmsg); 236cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 237cabdff1aSopenharmony_ci goto done; 238cabdff1aSopenharmony_cifail: 239cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, 240cabdff1aSopenharmony_ci "Device creation failed: %d.\n", err); 241cabdff1aSopenharmony_ci av_buffer_unref(&device_ref); 242cabdff1aSopenharmony_ci goto done; 243cabdff1aSopenharmony_ci} 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_cistatic int hw_device_init_from_type(enum AVHWDeviceType type, 246cabdff1aSopenharmony_ci const char *device, 247cabdff1aSopenharmony_ci HWDevice **dev_out) 248cabdff1aSopenharmony_ci{ 249cabdff1aSopenharmony_ci AVBufferRef *device_ref = NULL; 250cabdff1aSopenharmony_ci HWDevice *dev; 251cabdff1aSopenharmony_ci char *name; 252cabdff1aSopenharmony_ci int err; 253cabdff1aSopenharmony_ci 254cabdff1aSopenharmony_ci name = hw_device_default_name(type); 255cabdff1aSopenharmony_ci if (!name) { 256cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 257cabdff1aSopenharmony_ci goto fail; 258cabdff1aSopenharmony_ci } 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_ci err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0); 261cabdff1aSopenharmony_ci if (err < 0) { 262cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, 263cabdff1aSopenharmony_ci "Device creation failed: %d.\n", err); 264cabdff1aSopenharmony_ci goto fail; 265cabdff1aSopenharmony_ci } 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci dev = hw_device_add(); 268cabdff1aSopenharmony_ci if (!dev) { 269cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 270cabdff1aSopenharmony_ci goto fail; 271cabdff1aSopenharmony_ci } 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_ci dev->name = name; 274cabdff1aSopenharmony_ci dev->type = type; 275cabdff1aSopenharmony_ci dev->device_ref = device_ref; 276cabdff1aSopenharmony_ci 277cabdff1aSopenharmony_ci if (dev_out) 278cabdff1aSopenharmony_ci *dev_out = dev; 279cabdff1aSopenharmony_ci 280cabdff1aSopenharmony_ci return 0; 281cabdff1aSopenharmony_ci 282cabdff1aSopenharmony_cifail: 283cabdff1aSopenharmony_ci av_freep(&name); 284cabdff1aSopenharmony_ci av_buffer_unref(&device_ref); 285cabdff1aSopenharmony_ci return err; 286cabdff1aSopenharmony_ci} 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_civoid hw_device_free_all(void) 289cabdff1aSopenharmony_ci{ 290cabdff1aSopenharmony_ci int i; 291cabdff1aSopenharmony_ci for (i = 0; i < nb_hw_devices; i++) { 292cabdff1aSopenharmony_ci av_freep(&hw_devices[i]->name); 293cabdff1aSopenharmony_ci av_buffer_unref(&hw_devices[i]->device_ref); 294cabdff1aSopenharmony_ci av_freep(&hw_devices[i]); 295cabdff1aSopenharmony_ci } 296cabdff1aSopenharmony_ci av_freep(&hw_devices); 297cabdff1aSopenharmony_ci nb_hw_devices = 0; 298cabdff1aSopenharmony_ci} 299cabdff1aSopenharmony_ci 300cabdff1aSopenharmony_cistatic HWDevice *hw_device_match_by_codec(const AVCodec *codec) 301cabdff1aSopenharmony_ci{ 302cabdff1aSopenharmony_ci const AVCodecHWConfig *config; 303cabdff1aSopenharmony_ci HWDevice *dev; 304cabdff1aSopenharmony_ci int i; 305cabdff1aSopenharmony_ci for (i = 0;; i++) { 306cabdff1aSopenharmony_ci config = avcodec_get_hw_config(codec, i); 307cabdff1aSopenharmony_ci if (!config) 308cabdff1aSopenharmony_ci return NULL; 309cabdff1aSopenharmony_ci if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) 310cabdff1aSopenharmony_ci continue; 311cabdff1aSopenharmony_ci dev = hw_device_get_by_type(config->device_type); 312cabdff1aSopenharmony_ci if (dev) 313cabdff1aSopenharmony_ci return dev; 314cabdff1aSopenharmony_ci } 315cabdff1aSopenharmony_ci} 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ciint hw_device_setup_for_decode(InputStream *ist) 318cabdff1aSopenharmony_ci{ 319cabdff1aSopenharmony_ci const AVCodecHWConfig *config; 320cabdff1aSopenharmony_ci enum AVHWDeviceType type; 321cabdff1aSopenharmony_ci HWDevice *dev = NULL; 322cabdff1aSopenharmony_ci int err, auto_device = 0; 323cabdff1aSopenharmony_ci 324cabdff1aSopenharmony_ci if (ist->hwaccel_device) { 325cabdff1aSopenharmony_ci dev = hw_device_get_by_name(ist->hwaccel_device); 326cabdff1aSopenharmony_ci if (!dev) { 327cabdff1aSopenharmony_ci if (ist->hwaccel_id == HWACCEL_AUTO) { 328cabdff1aSopenharmony_ci auto_device = 1; 329cabdff1aSopenharmony_ci } else if (ist->hwaccel_id == HWACCEL_GENERIC) { 330cabdff1aSopenharmony_ci type = ist->hwaccel_device_type; 331cabdff1aSopenharmony_ci err = hw_device_init_from_type(type, ist->hwaccel_device, 332cabdff1aSopenharmony_ci &dev); 333cabdff1aSopenharmony_ci } else { 334cabdff1aSopenharmony_ci // This will be dealt with by API-specific initialisation 335cabdff1aSopenharmony_ci // (using hwaccel_device), so nothing further needed here. 336cabdff1aSopenharmony_ci return 0; 337cabdff1aSopenharmony_ci } 338cabdff1aSopenharmony_ci } else { 339cabdff1aSopenharmony_ci if (ist->hwaccel_id == HWACCEL_AUTO) { 340cabdff1aSopenharmony_ci ist->hwaccel_device_type = dev->type; 341cabdff1aSopenharmony_ci } else if (ist->hwaccel_device_type != dev->type) { 342cabdff1aSopenharmony_ci av_log(ist->dec_ctx, AV_LOG_ERROR, "Invalid hwaccel device " 343cabdff1aSopenharmony_ci "specified for decoder: device %s of type %s is not " 344cabdff1aSopenharmony_ci "usable with hwaccel %s.\n", dev->name, 345cabdff1aSopenharmony_ci av_hwdevice_get_type_name(dev->type), 346cabdff1aSopenharmony_ci av_hwdevice_get_type_name(ist->hwaccel_device_type)); 347cabdff1aSopenharmony_ci return AVERROR(EINVAL); 348cabdff1aSopenharmony_ci } 349cabdff1aSopenharmony_ci } 350cabdff1aSopenharmony_ci } else { 351cabdff1aSopenharmony_ci if (ist->hwaccel_id == HWACCEL_AUTO) { 352cabdff1aSopenharmony_ci auto_device = 1; 353cabdff1aSopenharmony_ci } else if (ist->hwaccel_id == HWACCEL_GENERIC) { 354cabdff1aSopenharmony_ci type = ist->hwaccel_device_type; 355cabdff1aSopenharmony_ci dev = hw_device_get_by_type(type); 356cabdff1aSopenharmony_ci 357cabdff1aSopenharmony_ci // When "-qsv_device device" is used, an internal QSV device named 358cabdff1aSopenharmony_ci // as "__qsv_device" is created. Another QSV device is created too 359cabdff1aSopenharmony_ci // if "-init_hw_device qsv=name:device" is used. There are 2 QSV devices 360cabdff1aSopenharmony_ci // if both "-qsv_device device" and "-init_hw_device qsv=name:device" 361cabdff1aSopenharmony_ci // are used, hw_device_get_by_type(AV_HWDEVICE_TYPE_QSV) returns NULL. 362cabdff1aSopenharmony_ci // To keep back-compatibility with the removed ad-hoc libmfx setup code, 363cabdff1aSopenharmony_ci // call hw_device_get_by_name("__qsv_device") to select the internal QSV 364cabdff1aSopenharmony_ci // device. 365cabdff1aSopenharmony_ci if (!dev && type == AV_HWDEVICE_TYPE_QSV) 366cabdff1aSopenharmony_ci dev = hw_device_get_by_name("__qsv_device"); 367cabdff1aSopenharmony_ci 368cabdff1aSopenharmony_ci if (!dev) 369cabdff1aSopenharmony_ci err = hw_device_init_from_type(type, NULL, &dev); 370cabdff1aSopenharmony_ci } else { 371cabdff1aSopenharmony_ci dev = hw_device_match_by_codec(ist->dec); 372cabdff1aSopenharmony_ci if (!dev) { 373cabdff1aSopenharmony_ci // No device for this codec, but not using generic hwaccel 374cabdff1aSopenharmony_ci // and therefore may well not need one - ignore. 375cabdff1aSopenharmony_ci return 0; 376cabdff1aSopenharmony_ci } 377cabdff1aSopenharmony_ci } 378cabdff1aSopenharmony_ci } 379cabdff1aSopenharmony_ci 380cabdff1aSopenharmony_ci if (auto_device) { 381cabdff1aSopenharmony_ci int i; 382cabdff1aSopenharmony_ci if (!avcodec_get_hw_config(ist->dec, 0)) { 383cabdff1aSopenharmony_ci // Decoder does not support any hardware devices. 384cabdff1aSopenharmony_ci return 0; 385cabdff1aSopenharmony_ci } 386cabdff1aSopenharmony_ci for (i = 0; !dev; i++) { 387cabdff1aSopenharmony_ci config = avcodec_get_hw_config(ist->dec, i); 388cabdff1aSopenharmony_ci if (!config) 389cabdff1aSopenharmony_ci break; 390cabdff1aSopenharmony_ci type = config->device_type; 391cabdff1aSopenharmony_ci dev = hw_device_get_by_type(type); 392cabdff1aSopenharmony_ci if (dev) { 393cabdff1aSopenharmony_ci av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto " 394cabdff1aSopenharmony_ci "hwaccel type %s with existing device %s.\n", 395cabdff1aSopenharmony_ci av_hwdevice_get_type_name(type), dev->name); 396cabdff1aSopenharmony_ci } 397cabdff1aSopenharmony_ci } 398cabdff1aSopenharmony_ci for (i = 0; !dev; i++) { 399cabdff1aSopenharmony_ci config = avcodec_get_hw_config(ist->dec, i); 400cabdff1aSopenharmony_ci if (!config) 401cabdff1aSopenharmony_ci break; 402cabdff1aSopenharmony_ci type = config->device_type; 403cabdff1aSopenharmony_ci // Try to make a new device of this type. 404cabdff1aSopenharmony_ci err = hw_device_init_from_type(type, ist->hwaccel_device, 405cabdff1aSopenharmony_ci &dev); 406cabdff1aSopenharmony_ci if (err < 0) { 407cabdff1aSopenharmony_ci // Can't make a device of this type. 408cabdff1aSopenharmony_ci continue; 409cabdff1aSopenharmony_ci } 410cabdff1aSopenharmony_ci if (ist->hwaccel_device) { 411cabdff1aSopenharmony_ci av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto " 412cabdff1aSopenharmony_ci "hwaccel type %s with new device created " 413cabdff1aSopenharmony_ci "from %s.\n", av_hwdevice_get_type_name(type), 414cabdff1aSopenharmony_ci ist->hwaccel_device); 415cabdff1aSopenharmony_ci } else { 416cabdff1aSopenharmony_ci av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto " 417cabdff1aSopenharmony_ci "hwaccel type %s with new default device.\n", 418cabdff1aSopenharmony_ci av_hwdevice_get_type_name(type)); 419cabdff1aSopenharmony_ci } 420cabdff1aSopenharmony_ci } 421cabdff1aSopenharmony_ci if (dev) { 422cabdff1aSopenharmony_ci ist->hwaccel_device_type = type; 423cabdff1aSopenharmony_ci } else { 424cabdff1aSopenharmony_ci av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel " 425cabdff1aSopenharmony_ci "disabled: no device found.\n"); 426cabdff1aSopenharmony_ci ist->hwaccel_id = HWACCEL_NONE; 427cabdff1aSopenharmony_ci return 0; 428cabdff1aSopenharmony_ci } 429cabdff1aSopenharmony_ci } 430cabdff1aSopenharmony_ci 431cabdff1aSopenharmony_ci if (!dev) { 432cabdff1aSopenharmony_ci av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available " 433cabdff1aSopenharmony_ci "for decoder: device type %s needed for codec %s.\n", 434cabdff1aSopenharmony_ci av_hwdevice_get_type_name(type), ist->dec->name); 435cabdff1aSopenharmony_ci return err; 436cabdff1aSopenharmony_ci } 437cabdff1aSopenharmony_ci 438cabdff1aSopenharmony_ci ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); 439cabdff1aSopenharmony_ci if (!ist->dec_ctx->hw_device_ctx) 440cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 441cabdff1aSopenharmony_ci 442cabdff1aSopenharmony_ci return 0; 443cabdff1aSopenharmony_ci} 444cabdff1aSopenharmony_ci 445cabdff1aSopenharmony_ciint hw_device_setup_for_encode(OutputStream *ost) 446cabdff1aSopenharmony_ci{ 447cabdff1aSopenharmony_ci const AVCodecHWConfig *config; 448cabdff1aSopenharmony_ci HWDevice *dev = NULL; 449cabdff1aSopenharmony_ci AVBufferRef *frames_ref = NULL; 450cabdff1aSopenharmony_ci int i; 451cabdff1aSopenharmony_ci 452cabdff1aSopenharmony_ci if (ost->filter) { 453cabdff1aSopenharmony_ci frames_ref = av_buffersink_get_hw_frames_ctx(ost->filter->filter); 454cabdff1aSopenharmony_ci if (frames_ref && 455cabdff1aSopenharmony_ci ((AVHWFramesContext*)frames_ref->data)->format == 456cabdff1aSopenharmony_ci ost->enc_ctx->pix_fmt) { 457cabdff1aSopenharmony_ci // Matching format, will try to use hw_frames_ctx. 458cabdff1aSopenharmony_ci } else { 459cabdff1aSopenharmony_ci frames_ref = NULL; 460cabdff1aSopenharmony_ci } 461cabdff1aSopenharmony_ci } 462cabdff1aSopenharmony_ci 463cabdff1aSopenharmony_ci for (i = 0;; i++) { 464cabdff1aSopenharmony_ci config = avcodec_get_hw_config(ost->enc, i); 465cabdff1aSopenharmony_ci if (!config) 466cabdff1aSopenharmony_ci break; 467cabdff1aSopenharmony_ci 468cabdff1aSopenharmony_ci if (frames_ref && 469cabdff1aSopenharmony_ci config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX && 470cabdff1aSopenharmony_ci (config->pix_fmt == AV_PIX_FMT_NONE || 471cabdff1aSopenharmony_ci config->pix_fmt == ost->enc_ctx->pix_fmt)) { 472cabdff1aSopenharmony_ci av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using input " 473cabdff1aSopenharmony_ci "frames context (format %s) with %s encoder.\n", 474cabdff1aSopenharmony_ci av_get_pix_fmt_name(ost->enc_ctx->pix_fmt), 475cabdff1aSopenharmony_ci ost->enc->name); 476cabdff1aSopenharmony_ci ost->enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref); 477cabdff1aSopenharmony_ci if (!ost->enc_ctx->hw_frames_ctx) 478cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 479cabdff1aSopenharmony_ci return 0; 480cabdff1aSopenharmony_ci } 481cabdff1aSopenharmony_ci 482cabdff1aSopenharmony_ci if (!dev && 483cabdff1aSopenharmony_ci config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) 484cabdff1aSopenharmony_ci dev = hw_device_get_by_type(config->device_type); 485cabdff1aSopenharmony_ci } 486cabdff1aSopenharmony_ci 487cabdff1aSopenharmony_ci if (dev) { 488cabdff1aSopenharmony_ci av_log(ost->enc_ctx, AV_LOG_VERBOSE, "Using device %s " 489cabdff1aSopenharmony_ci "(type %s) with %s encoder.\n", dev->name, 490cabdff1aSopenharmony_ci av_hwdevice_get_type_name(dev->type), ost->enc->name); 491cabdff1aSopenharmony_ci ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); 492cabdff1aSopenharmony_ci if (!ost->enc_ctx->hw_device_ctx) 493cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 494cabdff1aSopenharmony_ci } else { 495cabdff1aSopenharmony_ci // No device required, or no device available. 496cabdff1aSopenharmony_ci } 497cabdff1aSopenharmony_ci return 0; 498cabdff1aSopenharmony_ci} 499cabdff1aSopenharmony_ci 500cabdff1aSopenharmony_cistatic int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input) 501cabdff1aSopenharmony_ci{ 502cabdff1aSopenharmony_ci InputStream *ist = avctx->opaque; 503cabdff1aSopenharmony_ci AVFrame *output = NULL; 504cabdff1aSopenharmony_ci enum AVPixelFormat output_format = ist->hwaccel_output_format; 505cabdff1aSopenharmony_ci int err; 506cabdff1aSopenharmony_ci 507cabdff1aSopenharmony_ci if (input->format == output_format) { 508cabdff1aSopenharmony_ci // Nothing to do. 509cabdff1aSopenharmony_ci return 0; 510cabdff1aSopenharmony_ci } 511cabdff1aSopenharmony_ci 512cabdff1aSopenharmony_ci output = av_frame_alloc(); 513cabdff1aSopenharmony_ci if (!output) 514cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 515cabdff1aSopenharmony_ci 516cabdff1aSopenharmony_ci output->format = output_format; 517cabdff1aSopenharmony_ci 518cabdff1aSopenharmony_ci err = av_hwframe_transfer_data(output, input, 0); 519cabdff1aSopenharmony_ci if (err < 0) { 520cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to " 521cabdff1aSopenharmony_ci "output frame: %d.\n", err); 522cabdff1aSopenharmony_ci goto fail; 523cabdff1aSopenharmony_ci } 524cabdff1aSopenharmony_ci 525cabdff1aSopenharmony_ci err = av_frame_copy_props(output, input); 526cabdff1aSopenharmony_ci if (err < 0) { 527cabdff1aSopenharmony_ci av_frame_unref(output); 528cabdff1aSopenharmony_ci goto fail; 529cabdff1aSopenharmony_ci } 530cabdff1aSopenharmony_ci 531cabdff1aSopenharmony_ci av_frame_unref(input); 532cabdff1aSopenharmony_ci av_frame_move_ref(input, output); 533cabdff1aSopenharmony_ci av_frame_free(&output); 534cabdff1aSopenharmony_ci 535cabdff1aSopenharmony_ci return 0; 536cabdff1aSopenharmony_ci 537cabdff1aSopenharmony_cifail: 538cabdff1aSopenharmony_ci av_frame_free(&output); 539cabdff1aSopenharmony_ci return err; 540cabdff1aSopenharmony_ci} 541cabdff1aSopenharmony_ci 542cabdff1aSopenharmony_ciint hwaccel_decode_init(AVCodecContext *avctx) 543cabdff1aSopenharmony_ci{ 544cabdff1aSopenharmony_ci InputStream *ist = avctx->opaque; 545cabdff1aSopenharmony_ci 546cabdff1aSopenharmony_ci ist->hwaccel_retrieve_data = &hwaccel_retrieve_data; 547cabdff1aSopenharmony_ci 548cabdff1aSopenharmony_ci return 0; 549cabdff1aSopenharmony_ci} 550cabdff1aSopenharmony_ci 551cabdff1aSopenharmony_ciint hw_device_setup_for_filter(FilterGraph *fg) 552cabdff1aSopenharmony_ci{ 553cabdff1aSopenharmony_ci HWDevice *dev; 554cabdff1aSopenharmony_ci int i; 555cabdff1aSopenharmony_ci 556cabdff1aSopenharmony_ci // Pick the last hardware device if the user doesn't pick the device for 557cabdff1aSopenharmony_ci // filters explicitly with the filter_hw_device option. 558cabdff1aSopenharmony_ci if (filter_hw_device) 559cabdff1aSopenharmony_ci dev = filter_hw_device; 560cabdff1aSopenharmony_ci else if (nb_hw_devices > 0) { 561cabdff1aSopenharmony_ci dev = hw_devices[nb_hw_devices - 1]; 562cabdff1aSopenharmony_ci 563cabdff1aSopenharmony_ci if (nb_hw_devices > 1) 564cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_WARNING, "There are %d hardware devices. device " 565cabdff1aSopenharmony_ci "%s of type %s is picked for filters by default. Set hardware " 566cabdff1aSopenharmony_ci "device explicitly with the filter_hw_device option if device " 567cabdff1aSopenharmony_ci "%s is not usable for filters.\n", 568cabdff1aSopenharmony_ci nb_hw_devices, dev->name, 569cabdff1aSopenharmony_ci av_hwdevice_get_type_name(dev->type), dev->name); 570cabdff1aSopenharmony_ci } else 571cabdff1aSopenharmony_ci dev = NULL; 572cabdff1aSopenharmony_ci 573cabdff1aSopenharmony_ci if (dev) { 574cabdff1aSopenharmony_ci for (i = 0; i < fg->graph->nb_filters; i++) { 575cabdff1aSopenharmony_ci fg->graph->filters[i]->hw_device_ctx = 576cabdff1aSopenharmony_ci av_buffer_ref(dev->device_ref); 577cabdff1aSopenharmony_ci if (!fg->graph->filters[i]->hw_device_ctx) 578cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 579cabdff1aSopenharmony_ci } 580cabdff1aSopenharmony_ci } 581cabdff1aSopenharmony_ci 582cabdff1aSopenharmony_ci return 0; 583cabdff1aSopenharmony_ci} 584