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