GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/fftools/ffmpeg_hw.c Lines: 30 265 11.3 %
Date: 2019-11-22 03:34:36 Branches: 11 136 8.1 %

Line Branch Exec Source
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;
26
static HWDevice **hw_devices;
27
28
1593
static HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
29
{
30
1593
    HWDevice *found = NULL;
31
    int i;
32
1593
    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
1593
    return found;
40
}
41
42
HWDevice *hw_device_get_by_name(const char *name)
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
67
static char *hw_device_default_name(enum AVHWDeviceType type)
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
101
    AVDictionary *options = NULL;
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:
218
    av_log(NULL, AV_LOG_ERROR,
219
           "Invalid device specification \"%s\": %s\n", arg, errmsg);
220
    err = AVERROR(EINVAL);
221
    goto done;
222
fail:
223
    av_log(NULL, AV_LOG_ERROR,
224
           "Device creation failed: %d.\n", err);
225
    av_buffer_unref(&device_ref);
226
    goto done;
227
}
228
229
static int hw_device_init_from_type(enum AVHWDeviceType type,
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) {
246
        av_log(NULL, AV_LOG_ERROR,
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
272
5840
void hw_device_free_all(void)
273
{
274
    int i;
275
5840
    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
5840
    av_freep(&hw_devices);
281
5840
    nb_hw_devices = 0;
282
5840
}
283
284
11403
static HWDevice *hw_device_match_by_codec(const AVCodec *codec)
285
{
286
    const AVCodecHWConfig *config;
287
    HWDevice *dev;
288
    int i;
289
11403
    for (i = 0;; i++) {
290
12996
        config = avcodec_get_hw_config(codec, i);
291
12996
        if (!config)
292
11403
            return NULL;
293
1593
        if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
294
            continue;
295
1593
        dev = hw_device_get_by_type(config->device_type);
296
1593
        if (dev)
297
            return dev;
298
    }
299
}
300
301
5691
int hw_device_setup_for_decode(InputStream *ist)
302
{
303
    const AVCodecHWConfig *config;
304
    enum AVHWDeviceType type;
305
5691
    HWDevice *dev = NULL;
306
5691
    int err, auto_device = 0;
307
308
5691
    if (ist->hwaccel_device) {
309
        dev = hw_device_get_by_name(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,
329
                       av_hwdevice_get_type_name(dev->type),
330
                       av_hwdevice_get_type_name(ist->hwaccel_device_type));
331
                return AVERROR(EINVAL);
332
            }
333
        }
334
    } else {
335
5691
        if (ist->hwaccel_id == HWACCEL_AUTO) {
336
            auto_device = 1;
337
5691
        } 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
5691
            dev = hw_device_match_by_codec(ist->dec);
344
5691
            if (!dev) {
345
                // No device for this codec, but not using generic hwaccel
346
                // and therefore may well not need one - ignore.
347
5691
                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",
390
                       av_hwdevice_get_type_name(type));
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
410
    ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
411
    if (!ist->dec_ctx->hw_device_ctx)
412
        return AVERROR(ENOMEM);
413
414
    return 0;
415
}
416
417
5712
int hw_device_setup_for_encode(OutputStream *ost)
418
{
419
    HWDevice *dev;
420
421
5712
    dev = hw_device_match_by_codec(ost->enc);
422
5712
    if (dev) {
423
        ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
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
5712
        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
475
int hwaccel_decode_init(AVCodecContext *avctx)
476
{
477
    InputStream *ist = avctx->opaque;
478
479
    ist->hwaccel_retrieve_data = &hwaccel_retrieve_data;
480
481
    return 0;
482
}