FFmpeg  4.0
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  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  device = av_strndup(p, q - p);
159  if (!device) {
160  err = AVERROR(ENOMEM);
161  goto fail;
162  }
163  err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
164  if (err < 0) {
165  errmsg = "failed to parse options";
166  goto invalid;
167  }
168  }
169 
170  err = av_hwdevice_ctx_create(&device_ref, type,
171  device ? device : p, options, 0);
172  if (err < 0)
173  goto fail;
174 
175  } else if (*p == '@') {
176  // Derive from existing device.
177 
178  src = hw_device_get_by_name(p + 1);
179  if (!src) {
180  errmsg = "invalid source device name";
181  goto invalid;
182  }
183 
184  err = av_hwdevice_ctx_create_derived(&device_ref, type,
185  src->device_ref, 0);
186  if (err < 0)
187  goto fail;
188  } else {
189  errmsg = "parse error";
190  goto invalid;
191  }
192 
193  dev = hw_device_add();
194  if (!dev) {
195  err = AVERROR(ENOMEM);
196  goto fail;
197  }
198 
199  dev->name = name;
200  dev->type = type;
201  dev->device_ref = device_ref;
202 
203  if (dev_out)
204  *dev_out = dev;
205 
206  name = NULL;
207  err = 0;
208 done:
209  av_freep(&type_name);
210  av_freep(&name);
211  av_freep(&device);
212  av_dict_free(&options);
213  return err;
214 invalid:
216  "Invalid device specification \"%s\": %s\n", arg, errmsg);
217  err = AVERROR(EINVAL);
218  goto done;
219 fail:
221  "Device creation failed: %d.\n", err);
222  av_buffer_unref(&device_ref);
223  goto done;
224 }
225 
227  const char *device,
228  HWDevice **dev_out)
229 {
230  AVBufferRef *device_ref = NULL;
231  HWDevice *dev;
232  char *name;
233  int err;
234 
235  name = hw_device_default_name(type);
236  if (!name) {
237  err = AVERROR(ENOMEM);
238  goto fail;
239  }
240 
241  err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
242  if (err < 0) {
244  "Device creation failed: %d.\n", err);
245  goto fail;
246  }
247 
248  dev = hw_device_add();
249  if (!dev) {
250  err = AVERROR(ENOMEM);
251  goto fail;
252  }
253 
254  dev->name = name;
255  dev->type = type;
256  dev->device_ref = device_ref;
257 
258  if (dev_out)
259  *dev_out = dev;
260 
261  return 0;
262 
263 fail:
264  av_freep(&name);
265  av_buffer_unref(&device_ref);
266  return err;
267 }
268 
270 {
271  int i;
272  for (i = 0; i < nb_hw_devices; i++) {
273  av_freep(&hw_devices[i]->name);
274  av_buffer_unref(&hw_devices[i]->device_ref);
275  av_freep(&hw_devices[i]);
276  }
277  av_freep(&hw_devices);
278  nb_hw_devices = 0;
279 }
280 
282 {
283  const AVCodecHWConfig *config;
284  HWDevice *dev;
285  int i;
286  for (i = 0;; i++) {
287  config = avcodec_get_hw_config(codec, i);
288  if (!config)
289  return NULL;
291  continue;
292  dev = hw_device_get_by_type(config->device_type);
293  if (dev)
294  return dev;
295  }
296 }
297 
299 {
300  const AVCodecHWConfig *config;
301  enum AVHWDeviceType type;
302  HWDevice *dev = NULL;
303  int err, auto_device = 0;
304 
305  if (ist->hwaccel_device) {
307  if (!dev) {
308  if (ist->hwaccel_id == HWACCEL_AUTO) {
309  auto_device = 1;
310  } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
311  type = ist->hwaccel_device_type;
312  err = hw_device_init_from_type(type, ist->hwaccel_device,
313  &dev);
314  } else {
315  // This will be dealt with by API-specific initialisation
316  // (using hwaccel_device), so nothing further needed here.
317  return 0;
318  }
319  } else {
320  if (ist->hwaccel_id == HWACCEL_AUTO) {
321  ist->hwaccel_device_type = dev->type;
322  } else if (ist->hwaccel_device_type != dev->type) {
323  av_log(ist->dec_ctx, AV_LOG_ERROR, "Invalid hwaccel device "
324  "specified for decoder: device %s of type %s is not "
325  "usable with hwaccel %s.\n", dev->name,
328  return AVERROR(EINVAL);
329  }
330  }
331  } else {
332  if (ist->hwaccel_id == HWACCEL_AUTO) {
333  auto_device = 1;
334  } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
335  type = ist->hwaccel_device_type;
336  dev = hw_device_get_by_type(type);
337  if (!dev)
338  err = hw_device_init_from_type(type, NULL, &dev);
339  } else {
340  dev = hw_device_match_by_codec(ist->dec);
341  if (!dev) {
342  // No device for this codec, but not using generic hwaccel
343  // and therefore may well not need one - ignore.
344  return 0;
345  }
346  }
347  }
348 
349  if (auto_device) {
350  int i;
351  if (!avcodec_get_hw_config(ist->dec, 0)) {
352  // Decoder does not support any hardware devices.
353  return 0;
354  }
355  for (i = 0; !dev; i++) {
356  config = avcodec_get_hw_config(ist->dec, i);
357  if (!config)
358  break;
359  type = config->device_type;
360  dev = hw_device_get_by_type(type);
361  if (dev) {
362  av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
363  "hwaccel type %s with existing device %s.\n",
364  av_hwdevice_get_type_name(type), dev->name);
365  }
366  }
367  for (i = 0; !dev; i++) {
368  config = avcodec_get_hw_config(ist->dec, i);
369  if (!config)
370  break;
371  type = config->device_type;
372  // Try to make a new device of this type.
373  err = hw_device_init_from_type(type, ist->hwaccel_device,
374  &dev);
375  if (err < 0) {
376  // Can't make a device of this type.
377  continue;
378  }
379  if (ist->hwaccel_device) {
380  av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
381  "hwaccel type %s with new device created "
382  "from %s.\n", av_hwdevice_get_type_name(type),
383  ist->hwaccel_device);
384  } else {
385  av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
386  "hwaccel type %s with new default device.\n",
388  }
389  }
390  if (dev) {
391  ist->hwaccel_device_type = type;
392  } else {
393  av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel "
394  "disabled: no device found.\n");
395  ist->hwaccel_id = HWACCEL_NONE;
396  return 0;
397  }
398  }
399 
400  if (!dev) {
401  av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available "
402  "for decoder: device type %s needed for codec %s.\n",
403  av_hwdevice_get_type_name(type), ist->dec->name);
404  return err;
405  }
406 
408  if (!ist->dec_ctx->hw_device_ctx)
409  return AVERROR(ENOMEM);
410 
411  return 0;
412 }
413 
415 {
416  HWDevice *dev;
417 
418  dev = hw_device_match_by_codec(ost->enc);
419  if (dev) {
421  if (!ost->enc_ctx->hw_device_ctx)
422  return AVERROR(ENOMEM);
423  return 0;
424  } else {
425  // No device required, or no device available.
426  return 0;
427  }
428 }
429 
430 static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
431 {
432  InputStream *ist = avctx->opaque;
433  AVFrame *output = NULL;
434  enum AVPixelFormat output_format = ist->hwaccel_output_format;
435  int err;
436 
437  if (input->format == output_format) {
438  // Nothing to do.
439  return 0;
440  }
441 
442  output = av_frame_alloc();
443  if (!output)
444  return AVERROR(ENOMEM);
445 
446  output->format = output_format;
447 
448  err = av_hwframe_transfer_data(output, input, 0);
449  if (err < 0) {
450  av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to "
451  "output frame: %d.\n", err);
452  goto fail;
453  }
454 
455  err = av_frame_copy_props(output, input);
456  if (err < 0) {
457  av_frame_unref(output);
458  goto fail;
459  }
460 
461  av_frame_unref(input);
462  av_frame_move_ref(input, output);
463  av_frame_free(&output);
464 
465  return 0;
466 
467 fail:
468  av_frame_free(&output);
469  return err;
470 }
471 
473 {
474  InputStream *ist = avctx->opaque;
475 
477 
478  return 0;
479 }
const char * name
Definition: avisynth_c.h:775
#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:218
enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name)
Look up an AVHWDeviceType by name.
Definition: hwcontext.c:78
char * name
Definition: ffmpeg.h:75
void av_frame_move_ref(AVFrame *dst, AVFrame *src)
Move everything contained in src to dst and reset src.
Definition: frame.c:580
#define src
Definition: vp8dsp.c:254
AVCodec.
Definition: avcodec.h:3408
static int hw_device_init_from_type(enum AVHWDeviceType type, const char *device, HWDevice **dev_out)
Definition: ffmpeg_hw.c:226
#define av_malloc(s)
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:189
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 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:269
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:3391
int hwaccel_decode_init(AVCodecContext *avctx)
Definition: ffmpeg_hw.c:472
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:3415
#define fail()
Definition: checkasm.h:116
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
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:291
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:1518
const AVCodecHWConfig * avcodec_get_hw_config(const AVCodec *codec, int index)
Retrieve supported hardware configurations for a codec.
Definition: utils.c:1747
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:298
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:551
static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
Definition: ffmpeg_hw.c:430
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:281
const OptionDef options[]
Definition: ffmpeg_opt.c:3292
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:3398
enum HWAccelID hwaccel_id
Definition: ffmpeg.h:364
int hw_device_setup_for_encode(OutputStream *ost)
Definition: ffmpeg_hw.c:414
AVBufferRef * hw_device_ctx
A reference to the AVHWDeviceContext describing the device which will be used by a hardware encoder/d...
Definition: avcodec.h:3249
AVPixelFormat
Pixel format.
Definition: pixfmt.h:60
The codec supports this format via the hw_device_ctx interface.
Definition: avcodec.h:3354
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:1560
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:652