FFmpeg  4.2.3
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 #include <string.h>
20 
21 #include "libavutil/avstring.h"
22 
23 #include "ffmpeg.h"
24 
25 static int nb_hw_devices;
27 
29 {
30  HWDevice *found = NULL;
31  int i;
32  for (i = 0; i < nb_hw_devices; i++) {
33  if (hw_devices[i]->type == type) {
34  if (found)
35  return NULL;
36  found = hw_devices[i];
37  }
38  }
39  return found;
40 }
41 
43 {
44  int i;
45  for (i = 0; i < nb_hw_devices; i++) {
46  if (!strcmp(hw_devices[i]->name, name))
47  return hw_devices[i];
48  }
49  return NULL;
50 }
51 
52 static HWDevice *hw_device_add(void)
53 {
54  int err;
55  err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,
56  sizeof(*hw_devices));
57  if (err) {
58  nb_hw_devices = 0;
59  return NULL;
60  }
61  hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));
62  if (!hw_devices[nb_hw_devices])
63  return NULL;
64  return hw_devices[nb_hw_devices++];
65 }
66 
68 {
69  // Make an automatic name of the form "type%d". We arbitrarily
70  // limit at 1000 anonymous devices of the same type - there is
71  // probably something else very wrong if you get to this limit.
72  const char *type_name = av_hwdevice_get_type_name(type);
73  char *name;
74  size_t index_pos;
75  int index, index_limit = 1000;
76  index_pos = strlen(type_name);
77  name = av_malloc(index_pos + 4);
78  if (!name)
79  return NULL;
80  for (index = 0; index < index_limit; index++) {
81  snprintf(name, index_pos + 4, "%s%d", type_name, index);
82  if (!hw_device_get_by_name(name))
83  break;
84  }
85  if (index >= index_limit) {
86  av_freep(&name);
87  return NULL;
88  }
89  return name;
90 }
91 
92 int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
93 {
94  // "type=name:device,key=value,key2=value2"
95  // "type:device,key=value,key2=value2"
96  // -> av_hwdevice_ctx_create()
97  // "type=name@name"
98  // "type@name"
99  // -> av_hwdevice_ctx_create_derived()
100 
102  const char *type_name = NULL, *name = NULL, *device = NULL;
103  enum AVHWDeviceType type;
104  HWDevice *dev, *src;
105  AVBufferRef *device_ref = NULL;
106  int err;
107  const char *errmsg, *p, *q;
108  size_t k;
109 
110  k = strcspn(arg, ":=@");
111  p = arg + k;
112 
113  type_name = av_strndup(arg, k);
114  if (!type_name) {
115  err = AVERROR(ENOMEM);
116  goto fail;
117  }
118  type = av_hwdevice_find_type_by_name(type_name);
119  if (type == AV_HWDEVICE_TYPE_NONE) {
120  errmsg = "unknown device type";
121  goto invalid;
122  }
123 
124  if (*p == '=') {
125  k = strcspn(p + 1, ":@");
126 
127  name = av_strndup(p + 1, k);
128  if (!name) {
129  err = AVERROR(ENOMEM);
130  goto fail;
131  }
132  if (hw_device_get_by_name(name)) {
133  errmsg = "named device already exists";
134  goto invalid;
135  }
136 
137  p += 1 + k;
138  } else {
139  name = hw_device_default_name(type);
140  if (!name) {
141  err = AVERROR(ENOMEM);
142  goto fail;
143  }
144  }
145 
146  if (!*p) {
147  // New device with no parameters.
148  err = av_hwdevice_ctx_create(&device_ref, type,
149  NULL, NULL, 0);
150  if (err < 0)
151  goto fail;
152 
153  } else if (*p == ':') {
154  // New device with some parameters.
155  ++p;
156  q = strchr(p, ',');
157  if (q) {
158  if (q - p > 0) {
159  device = av_strndup(p, q - p);
160  if (!device) {
161  err = AVERROR(ENOMEM);
162  goto fail;
163  }
164  }
165  err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
166  if (err < 0) {
167  errmsg = "failed to parse options";
168  goto invalid;
169  }
170  }
171 
172  err = av_hwdevice_ctx_create(&device_ref, type,
173  q ? device : p[0] ? p : NULL,
174  options, 0);
175  if (err < 0)
176  goto fail;
177 
178  } else if (*p == '@') {
179  // Derive from existing device.
180 
181  src = hw_device_get_by_name(p + 1);
182  if (!src) {
183  errmsg = "invalid source device name";
184  goto invalid;
185  }
186 
187  err = av_hwdevice_ctx_create_derived(&device_ref, type,
188  src->device_ref, 0);
189  if (err < 0)
190  goto fail;
191  } else {
192  errmsg = "parse error";
193  goto invalid;
194  }
195 
196  dev = hw_device_add();
197  if (!dev) {
198  err = AVERROR(ENOMEM);
199  goto fail;
200  }
201 
202  dev->name = name;
203  dev->type = type;
204  dev->device_ref = device_ref;
205 
206  if (dev_out)
207  *dev_out = dev;
208 
209  name = NULL;
210  err = 0;
211 done:
212  av_freep(&type_name);
213  av_freep(&name);
214  av_freep(&device);
215  av_dict_free(&options);
216  return err;
217 invalid:
219  "Invalid device specification \"%s\": %s\n", arg, errmsg);
220  err = AVERROR(EINVAL);
221  goto done;
222 fail:
224  "Device creation failed: %d.\n", err);
225  av_buffer_unref(&device_ref);
226  goto done;
227 }
228 
230  const char *device,
231  HWDevice **dev_out)
232 {
233  AVBufferRef *device_ref = NULL;
234  HWDevice *dev;
235  char *name;
236  int err;
237 
238  name = hw_device_default_name(type);
239  if (!name) {
240  err = AVERROR(ENOMEM);
241  goto fail;
242  }
243 
244  err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
245  if (err < 0) {
247  "Device creation failed: %d.\n", err);
248  goto fail;
249  }
250 
251  dev = hw_device_add();
252  if (!dev) {
253  err = AVERROR(ENOMEM);
254  goto fail;
255  }
256 
257  dev->name = name;
258  dev->type = type;
259  dev->device_ref = device_ref;
260 
261  if (dev_out)
262  *dev_out = dev;
263 
264  return 0;
265 
266 fail:
267  av_freep(&name);
268  av_buffer_unref(&device_ref);
269  return err;
270 }
271 
273 {
274  int i;
275  for (i = 0; i < nb_hw_devices; i++) {
276  av_freep(&hw_devices[i]->name);
277  av_buffer_unref(&hw_devices[i]->device_ref);
278  av_freep(&hw_devices[i]);
279  }
280  av_freep(&hw_devices);
281  nb_hw_devices = 0;
282 }
283 
285 {
286  const AVCodecHWConfig *config;
287  HWDevice *dev;
288  int i;
289  for (i = 0;; i++) {
290  config = avcodec_get_hw_config(codec, i);
291  if (!config)
292  return NULL;
294  continue;
295  dev = hw_device_get_by_type(config->device_type);
296  if (dev)
297  return dev;
298  }
299 }
300 
302 {
303  const AVCodecHWConfig *config;
304  enum AVHWDeviceType type;
305  HWDevice *dev = NULL;
306  int err, auto_device = 0;
307 
308  if (ist->hwaccel_device) {
310  if (!dev) {
311  if (ist->hwaccel_id == HWACCEL_AUTO) {
312  auto_device = 1;
313  } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
314  type = ist->hwaccel_device_type;
315  err = hw_device_init_from_type(type, ist->hwaccel_device,
316  &dev);
317  } else {
318  // This will be dealt with by API-specific initialisation
319  // (using hwaccel_device), so nothing further needed here.
320  return 0;
321  }
322  } else {
323  if (ist->hwaccel_id == HWACCEL_AUTO) {
324  ist->hwaccel_device_type = dev->type;
325  } else if (ist->hwaccel_device_type != dev->type) {
326  av_log(ist->dec_ctx, AV_LOG_ERROR, "Invalid hwaccel device "
327  "specified for decoder: device %s of type %s is not "
328  "usable with hwaccel %s.\n", dev->name,
331  return AVERROR(EINVAL);
332  }
333  }
334  } else {
335  if (ist->hwaccel_id == HWACCEL_AUTO) {
336  auto_device = 1;
337  } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
338  type = ist->hwaccel_device_type;
339  dev = hw_device_get_by_type(type);
340  if (!dev)
341  err = hw_device_init_from_type(type, NULL, &dev);
342  } else {
343  dev = hw_device_match_by_codec(ist->dec);
344  if (!dev) {
345  // No device for this codec, but not using generic hwaccel
346  // and therefore may well not need one - ignore.
347  return 0;
348  }
349  }
350  }
351 
352  if (auto_device) {
353  int i;
354  if (!avcodec_get_hw_config(ist->dec, 0)) {
355  // Decoder does not support any hardware devices.
356  return 0;
357  }
358  for (i = 0; !dev; i++) {
359  config = avcodec_get_hw_config(ist->dec, i);
360  if (!config)
361  break;
362  type = config->device_type;
363  dev = hw_device_get_by_type(type);
364  if (dev) {
365  av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
366  "hwaccel type %s with existing device %s.\n",
367  av_hwdevice_get_type_name(type), dev->name);
368  }
369  }
370  for (i = 0; !dev; i++) {
371  config = avcodec_get_hw_config(ist->dec, i);
372  if (!config)
373  break;
374  type = config->device_type;
375  // Try to make a new device of this type.
376  err = hw_device_init_from_type(type, ist->hwaccel_device,
377  &dev);
378  if (err < 0) {
379  // Can't make a device of this type.
380  continue;
381  }
382  if (ist->hwaccel_device) {
383  av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
384  "hwaccel type %s with new device created "
385  "from %s.\n", av_hwdevice_get_type_name(type),
386  ist->hwaccel_device);
387  } else {
388  av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
389  "hwaccel type %s with new default device.\n",
391  }
392  }
393  if (dev) {
394  ist->hwaccel_device_type = type;
395  } else {
396  av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel "
397  "disabled: no device found.\n");
398  ist->hwaccel_id = HWACCEL_NONE;
399  return 0;
400  }
401  }
402 
403  if (!dev) {
404  av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available "
405  "for decoder: device type %s needed for codec %s.\n",
406  av_hwdevice_get_type_name(type), ist->dec->name);
407  return err;
408  }
409 
411  if (!ist->dec_ctx->hw_device_ctx)
412  return AVERROR(ENOMEM);
413 
414  return 0;
415 }
416 
418 {
419  HWDevice *dev;
420 
421  dev = hw_device_match_by_codec(ost->enc);
422  if (dev) {
424  if (!ost->enc_ctx->hw_device_ctx)
425  return AVERROR(ENOMEM);
426  return 0;
427  } else {
428  // No device required, or no device available.
429  return 0;
430  }
431 }
432 
433 static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
434 {
435  InputStream *ist = avctx->opaque;
436  AVFrame *output = NULL;
437  enum AVPixelFormat output_format = ist->hwaccel_output_format;
438  int err;
439 
440  if (input->format == output_format) {
441  // Nothing to do.
442  return 0;
443  }
444 
445  output = av_frame_alloc();
446  if (!output)
447  return AVERROR(ENOMEM);
448 
449  output->format = output_format;
450 
451  err = av_hwframe_transfer_data(output, input, 0);
452  if (err < 0) {
453  av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to "
454  "output frame: %d.\n", err);
455  goto fail;
456  }
457 
458  err = av_frame_copy_props(output, input);
459  if (err < 0) {
460  av_frame_unref(output);
461  goto fail;
462  }
463 
464  av_frame_unref(input);
465  av_frame_move_ref(input, output);
466  av_frame_free(&output);
467 
468  return 0;
469 
470 fail:
471  av_frame_free(&output);
472  return err;
473 }
474 
476 {
477  InputStream *ist = avctx->opaque;
478 
480 
481  return 0;
482 }
const char * name
Definition: avisynth_c.h:867
#define NULL
Definition: coverity.c:32
static char * hw_device_default_name(enum AVHWDeviceType type)
Definition: ffmpeg_hw.c:67
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it...
Definition: buffer.c:125
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name)
Look up an AVHWDeviceType by name.
Definition: hwcontext.c:78
void av_frame_move_ref(AVFrame *dst, AVFrame *src)
Move everything contained in src to dst and reset src.
Definition: frame.c:582
#define src
Definition: vp8dsp.c:254
AVCodec.
Definition: avcodec.h:3481
static int hw_device_init_from_type(enum AVHWDeviceType type, const char *device, HWDevice **dev_out)
Definition: ffmpeg_hw.c:229
#define av_malloc(s)
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:189
The codec supports this format via the hw_device_ctx interface.
Definition: avcodec.h:3427
int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, const char *device, AVDictionary *opts, int flags)
Open a device of the specified type and create an AVHWDeviceContext for it.
Definition: hwcontext.c:571
AVCodec * dec
Definition: ffmpeg.h:305
#define av_log(a,...)
int(* hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame)
Definition: ffmpeg.h:373
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AVERROR(e)
Definition: error.h:43
static HWDevice * hw_device_add(void)
Definition: ffmpeg_hw.c:52
void hw_device_free_all(void)
Definition: ffmpeg_hw.c:272
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
int methods
Bit set of AV_CODEC_HW_CONFIG_METHOD_* flags, describing the possible setup methods which can be used...
Definition: avcodec.h:3464
int hwaccel_decode_init(AVCodecContext *avctx)
Definition: ffmpeg_hw.c:475
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:203
const char * arg
Definition: jacosubdec.c:66
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
const char * name
Name of the codec implementation.
Definition: avcodec.h:3488
#define fail()
Definition: checkasm.h:120
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
Allocate, reallocate, or free an array through a pointer to a pointer.
Definition: mem.c:205
const char * name
Definition: ffmpeg.h:75
int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags)
Copy data to or from a hw surface.
Definition: hwcontext.c:439
int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr, enum AVHWDeviceType type, AVBufferRef *src_ref, int flags)
Create a new device of the specified type from an existing device.
Definition: hwcontext.c:607
static int nb_hw_devices
Definition: ffmpeg_hw.c:25
AVCodecContext * enc
Definition: muxing.c:55
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:368
int av_dict_parse_string(AVDictionary **pm, const char *str, const char *key_val_sep, const char *pairs_sep, int flags)
Parse the key/value pairs list and add the parsed entries to a dictionary.
Definition: dict.c:180
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
enum AVHWDeviceType hwaccel_device_type
Definition: ffmpeg.h:365
main external API structure.
Definition: avcodec.h:1565
const AVCodecHWConfig * avcodec_get_hw_config(const AVCodec *codec, int index)
Retrieve supported hardware configurations for a codec.
Definition: utils.c:1784
HWDevice * hw_device_get_by_name(const char *name)
Definition: ffmpeg_hw.c:42
AVCodecContext * enc_ctx
Definition: ffmpeg.h:465
int hw_device_setup_for_decode(InputStream *ist)
Definition: ffmpeg_hw.c:301
const char * av_hwdevice_get_type_name(enum AVHWDeviceType type)
Get the string name of an AVHWDeviceType.
Definition: hwcontext.c:88
int index
Definition: gxfenc.c:89
AVCodecContext * dec_ctx
Definition: ffmpeg.h:304
cl_device_type type
static HWDevice ** hw_devices
Definition: ffmpeg_hw.c:26
#define snprintf
Definition: snprintf.h:34
static HWDevice * hw_device_get_by_type(enum AVHWDeviceType type)
Definition: ffmpeg_hw.c:28
enum AVPixelFormat hwaccel_output_format
Definition: ffmpeg.h:367
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:553
static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
Definition: ffmpeg_hw.c:433
A reference to a data buffer.
Definition: buffer.h:81
static AVStream * ost
static HWDevice * hw_device_match_by_codec(const AVCodec *codec)
Definition: ffmpeg_hw.c:284
const OptionDef options[]
Definition: ffmpeg_opt.c:3368
enum AVHWDeviceType type
Definition: ffmpeg.h:76
int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
Definition: ffmpeg_hw.c:92
AVBufferRef * device_ref
Definition: ffmpeg.h:77
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
AVHWDeviceType
Definition: hwcontext.h:27
char * hwaccel_device
Definition: ffmpeg.h:366
#define av_freep(p)
enum AVHWDeviceType device_type
The device type associated with the configuration.
Definition: avcodec.h:3471
enum HWAccelID hwaccel_id
Definition: ffmpeg.h:364
int hw_device_setup_for_encode(OutputStream *ost)
Definition: ffmpeg_hw.c:417
AVBufferRef * hw_device_ctx
A reference to the AVHWDeviceContext describing the device which will be used by a hardware encoder/d...
Definition: avcodec.h:3314
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
Definition: mem.c:263
void * opaque
Private data of the user, can be used to carry app specific stuff.
Definition: avcodec.h:1607
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:654