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