aarch64: Add assembly support for -fsanitize=hwaddress tagged globals.
[libav.git] / avtools / avconv_hw.c
blob7e223bf102547480c8d30782882fb88b875b63f8
1 /*
2 * This file is part of Libav.
4 * Libav 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.
9 * Libav 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.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with Libav; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include <string.h>
21 #include "avconv.h"
23 static int nb_hw_devices;
24 static HWDevice **hw_devices;
26 static HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
28 HWDevice *found = NULL;
29 int i;
30 for (i = 0; i < nb_hw_devices; i++) {
31 if (hw_devices[i]->type == type) {
32 if (found)
33 return NULL;
34 found = hw_devices[i];
37 return found;
40 HWDevice *hw_device_get_by_name(const char *name)
42 int i;
43 for (i = 0; i < nb_hw_devices; i++) {
44 if (!strcmp(hw_devices[i]->name, name))
45 return hw_devices[i];
47 return NULL;
50 static HWDevice *hw_device_add(void)
52 int err;
53 err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,
54 sizeof(*hw_devices));
55 if (err) {
56 nb_hw_devices = 0;
57 return NULL;
59 hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));
60 if (!hw_devices[nb_hw_devices])
61 return NULL;
62 return hw_devices[nb_hw_devices++];
65 static char *hw_device_default_name(enum AVHWDeviceType type)
67 // Make an automatic name of the form "type%d". We arbitrarily
68 // limit at 1000 anonymous devices of the same type - there is
69 // probably something else very wrong if you get to this limit.
70 const char *type_name = av_hwdevice_get_type_name(type);
71 char *name;
72 size_t index_pos;
73 int index, index_limit = 1000;
74 index_pos = strlen(type_name);
75 name = av_malloc(index_pos + 4);
76 if (!name)
77 return NULL;
78 for (index = 0; index < index_limit; index++) {
79 snprintf(name, index_pos + 4, "%s%d", type_name, index);
80 if (!hw_device_get_by_name(name))
81 break;
83 if (index >= index_limit) {
84 av_freep(&name);
85 return NULL;
87 return name;
90 int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
92 // "type=name:device,key=value,key2=value2"
93 // "type:device,key=value,key2=value2"
94 // -> av_hwdevice_ctx_create()
95 // "type=name@name"
96 // "type@name"
97 // -> av_hwdevice_ctx_create_derived()
99 AVDictionary *options = NULL;
100 char *type_name = NULL, *name = NULL, *device = NULL;
101 enum AVHWDeviceType type;
102 HWDevice *dev, *src;
103 AVBufferRef *device_ref = NULL;
104 int err;
105 const char *errmsg, *p, *q;
106 size_t k;
108 k = strcspn(arg, ":=@");
109 p = arg + k;
111 type_name = av_strndup(arg, k);
112 if (!type_name) {
113 err = AVERROR(ENOMEM);
114 goto fail;
116 type = av_hwdevice_find_type_by_name(type_name);
117 if (type == AV_HWDEVICE_TYPE_NONE) {
118 errmsg = "unknown device type";
119 goto invalid;
122 if (*p == '=') {
123 k = strcspn(p + 1, ":@");
125 name = av_strndup(p + 1, k);
126 if (!name) {
127 err = AVERROR(ENOMEM);
128 goto fail;
130 if (hw_device_get_by_name(name)) {
131 errmsg = "named device already exists";
132 goto invalid;
135 p += 1 + k;
136 } else {
137 name = hw_device_default_name(type);
138 if (!name) {
139 err = AVERROR(ENOMEM);
140 goto fail;
144 if (!*p) {
145 // New device with no parameters.
146 err = av_hwdevice_ctx_create(&device_ref, type,
147 NULL, NULL, 0);
148 if (err < 0)
149 goto fail;
151 } else if (*p == ':') {
152 // New device with some parameters.
153 ++p;
154 q = strchr(p, ',');
155 if (q) {
156 device = av_strndup(p, q - p);
157 if (!device) {
158 err = AVERROR(ENOMEM);
159 goto fail;
161 err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
162 if (err < 0) {
163 errmsg = "failed to parse options";
164 goto invalid;
168 err = av_hwdevice_ctx_create(&device_ref, type,
169 device ? device : p, options, 0);
170 if (err < 0)
171 goto fail;
173 } else if (*p == '@') {
174 // Derive from existing device.
176 src = hw_device_get_by_name(p + 1);
177 if (!src) {
178 errmsg = "invalid source device name";
179 goto invalid;
182 err = av_hwdevice_ctx_create_derived(&device_ref, type,
183 src->device_ref, 0);
184 if (err < 0)
185 goto fail;
186 } else {
187 errmsg = "parse error";
188 goto invalid;
191 dev = hw_device_add();
192 if (!dev) {
193 err = AVERROR(ENOMEM);
194 goto fail;
197 dev->name = name;
198 dev->type = type;
199 dev->device_ref = device_ref;
201 if (dev_out)
202 *dev_out = dev;
204 name = NULL;
205 err = 0;
206 done:
207 av_freep(&type_name);
208 av_freep(&name);
209 av_freep(&device);
210 av_dict_free(&options);
211 return err;
212 invalid:
213 av_log(NULL, AV_LOG_ERROR,
214 "Invalid device specification \"%s\": %s\n", arg, errmsg);
215 err = AVERROR(EINVAL);
216 goto done;
217 fail:
218 av_log(NULL, AV_LOG_ERROR,
219 "Device creation failed: %d.\n", err);
220 av_buffer_unref(&device_ref);
221 goto done;
224 static int hw_device_init_from_type(enum AVHWDeviceType type,
225 const char *device,
226 HWDevice **dev_out)
228 AVBufferRef *device_ref = NULL;
229 HWDevice *dev;
230 char *name;
231 int err;
233 name = hw_device_default_name(type);
234 if (!name) {
235 err = AVERROR(ENOMEM);
236 goto fail;
239 err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
240 if (err < 0) {
241 av_log(NULL, AV_LOG_ERROR,
242 "Device creation failed: %d.\n", err);
243 goto fail;
246 dev = hw_device_add();
247 if (!dev) {
248 err = AVERROR(ENOMEM);
249 goto fail;
252 dev->name = name;
253 dev->type = type;
254 dev->device_ref = device_ref;
256 if (dev_out)
257 *dev_out = dev;
259 return 0;
261 fail:
262 av_freep(&name);
263 av_buffer_unref(&device_ref);
264 return err;
267 void hw_device_free_all(void)
269 int i;
270 for (i = 0; i < nb_hw_devices; i++) {
271 av_freep(&hw_devices[i]->name);
272 av_buffer_unref(&hw_devices[i]->device_ref);
273 av_freep(&hw_devices[i]);
275 av_freep(&hw_devices);
276 nb_hw_devices = 0;
279 static HWDevice *hw_device_match_by_codec(const AVCodec *codec)
281 const AVCodecHWConfig *config;
282 HWDevice *dev;
283 int i;
284 for (i = 0;; i++) {
285 config = avcodec_get_hw_config(codec, i);
286 if (!config)
287 return NULL;
288 if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
289 continue;
290 dev = hw_device_get_by_type(config->device_type);
291 if (dev)
292 return dev;
296 int hw_device_setup_for_decode(InputStream *ist)
298 const AVCodecHWConfig *config;
299 enum AVHWDeviceType type;
300 HWDevice *dev = NULL;
301 int err, auto_device = 0;
303 if (ist->hwaccel_device) {
304 dev = hw_device_get_by_name(ist->hwaccel_device);
305 if (!dev) {
306 if (ist->hwaccel_id == HWACCEL_AUTO) {
307 auto_device = 1;
308 } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
309 type = ist->hwaccel_device_type;
310 err = hw_device_init_from_type(type, ist->hwaccel_device,
311 &dev);
312 } else {
313 // This will be dealt with by API-specific initialisation
314 // (using hwaccel_device), so nothing further needed here.
315 return 0;
317 } else {
318 if (ist->hwaccel_id == HWACCEL_AUTO) {
319 ist->hwaccel_device_type = dev->type;
320 } else if (ist->hwaccel_device_type != dev->type) {
321 av_log(ist->dec_ctx, AV_LOG_ERROR, "Invalid hwaccel device "
322 "specified for decoder: device %s of type %s is not "
323 "usable with hwaccel %s.\n", dev->name,
324 av_hwdevice_get_type_name(dev->type),
325 av_hwdevice_get_type_name(ist->hwaccel_device_type));
326 return AVERROR(EINVAL);
329 } else {
330 if (ist->hwaccel_id == HWACCEL_AUTO) {
331 auto_device = 1;
332 } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
333 type = ist->hwaccel_device_type;
334 dev = hw_device_get_by_type(type);
335 if (!dev)
336 err = hw_device_init_from_type(type, NULL, &dev);
337 } else {
338 dev = hw_device_match_by_codec(ist->dec);
339 if (!dev) {
340 // No device for this codec, but not using generic hwaccel
341 // and therefore may well not need one - ignore.
342 return 0;
347 if (auto_device) {
348 int i;
349 if (!avcodec_get_hw_config(ist->dec, 0)) {
350 // Decoder does not support any hardware devices.
351 return 0;
353 for (i = 0; !dev; i++) {
354 config = avcodec_get_hw_config(ist->dec, i);
355 if (!config)
356 break;
357 type = config->device_type;
358 dev = hw_device_get_by_type(type);
359 if (dev) {
360 av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
361 "hwaccel type %s with existing device %s.\n",
362 av_hwdevice_get_type_name(type), dev->name);
365 for (i = 0; !dev; i++) {
366 config = avcodec_get_hw_config(ist->dec, i);
367 if (!config)
368 break;
369 type = config->device_type;
370 // Try to make a new device of this type.
371 err = hw_device_init_from_type(type, ist->hwaccel_device,
372 &dev);
373 if (err < 0) {
374 // Can't make a device of this type.
375 continue;
377 if (ist->hwaccel_device) {
378 av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
379 "hwaccel type %s with new device created "
380 "from %s.\n", av_hwdevice_get_type_name(type),
381 ist->hwaccel_device);
382 } else {
383 av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
384 "hwaccel type %s with new default device.\n",
385 av_hwdevice_get_type_name(type));
388 if (dev) {
389 ist->hwaccel_device_type = type;
390 } else {
391 av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel "
392 "disabled: no device found.\n");
393 ist->hwaccel_id = HWACCEL_NONE;
394 return 0;
398 if (!dev) {
399 av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available "
400 "for decoder: device type %s needed for codec %s.\n",
401 av_hwdevice_get_type_name(type), ist->dec->name);
402 return err;
405 ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
406 if (!ist->dec_ctx->hw_device_ctx)
407 return AVERROR(ENOMEM);
409 return 0;
412 int hw_device_setup_for_encode(OutputStream *ost)
414 HWDevice *dev;
416 dev = hw_device_match_by_codec(ost->enc);
417 if (dev) {
418 ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
419 if (!ost->enc_ctx->hw_device_ctx)
420 return AVERROR(ENOMEM);
421 return 0;
422 } else {
423 // No device required, or no device available.
424 return 0;
428 static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
430 InputStream *ist = avctx->opaque;
431 AVFrame *output = NULL;
432 enum AVPixelFormat output_format = ist->hwaccel_output_format;
433 int err;
435 if (input->format == output_format) {
436 // Nothing to do.
437 return 0;
440 output = av_frame_alloc();
441 if (!output)
442 return AVERROR(ENOMEM);
444 output->format = output_format;
446 err = av_hwframe_transfer_data(output, input, 0);
447 if (err < 0) {
448 av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to "
449 "output frame: %d.\n", err);
450 goto fail;
453 err = av_frame_copy_props(output, input);
454 if (err < 0) {
455 av_frame_unref(output);
456 goto fail;
459 av_frame_unref(input);
460 av_frame_move_ref(input, output);
461 av_frame_free(&output);
463 return 0;
465 fail:
466 av_frame_free(&output);
467 return err;
470 int hwaccel_decode_init(AVCodecContext *avctx)
472 InputStream *ist = avctx->opaque;
474 ist->hwaccel_retrieve_data = &hwaccel_retrieve_data;
476 return 0;