Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavutil/hwcontext.c
Line
Count
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 "config.h"
20
21
#include "avassert.h"
22
#include "buffer.h"
23
#include "common.h"
24
#include "frame_internal.h"
25
#include "hwcontext.h"
26
#include "hwcontext_internal.h"
27
#include "imgutils.h"
28
#include "log.h"
29
#include "mem.h"
30
#include "pixdesc.h"
31
#include "pixfmt.h"
32
33
static const HWContextType * const hw_table[] = {
34
#if CONFIG_CUDA
35
    &ff_hwcontext_type_cuda,
36
#endif
37
#if CONFIG_D3D11VA
38
    &ff_hwcontext_type_d3d11va,
39
#endif
40
#if CONFIG_D3D12VA
41
    &ff_hwcontext_type_d3d12va,
42
#endif
43
#if CONFIG_LIBDRM
44
    &ff_hwcontext_type_drm,
45
#endif
46
#if CONFIG_DXVA2
47
    &ff_hwcontext_type_dxva2,
48
#endif
49
#if CONFIG_OPENCL
50
    &ff_hwcontext_type_opencl,
51
#endif
52
#if CONFIG_QSV
53
    &ff_hwcontext_type_qsv,
54
#endif
55
#if CONFIG_VAAPI
56
    &ff_hwcontext_type_vaapi,
57
#endif
58
#if CONFIG_VDPAU
59
    &ff_hwcontext_type_vdpau,
60
#endif
61
#if CONFIG_VIDEOTOOLBOX
62
    &ff_hwcontext_type_videotoolbox,
63
#endif
64
#if CONFIG_MEDIACODEC
65
    &ff_hwcontext_type_mediacodec,
66
#endif
67
#if CONFIG_VULKAN
68
    &ff_hwcontext_type_vulkan,
69
#endif
70
#if CONFIG_AMF
71
    &ff_hwcontext_type_amf,
72
#endif
73
#if CONFIG_OHCODEC
74
    &ff_hwcontext_type_oh,
75
#endif
76
    NULL,
77
};
78
79
static const char *const hw_type_names[] = {
80
    [AV_HWDEVICE_TYPE_CUDA]   = "cuda",
81
    [AV_HWDEVICE_TYPE_DRM]    = "drm",
82
    [AV_HWDEVICE_TYPE_DXVA2]  = "dxva2",
83
    [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va",
84
    [AV_HWDEVICE_TYPE_D3D12VA] = "d3d12va",
85
    [AV_HWDEVICE_TYPE_OPENCL] = "opencl",
86
    [AV_HWDEVICE_TYPE_QSV]    = "qsv",
87
    [AV_HWDEVICE_TYPE_VAAPI]  = "vaapi",
88
    [AV_HWDEVICE_TYPE_VDPAU]  = "vdpau",
89
    [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",
90
    [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",
91
    [AV_HWDEVICE_TYPE_VULKAN] = "vulkan",
92
    [AV_HWDEVICE_TYPE_AMF] = "amf",
93
    [AV_HWDEVICE_TYPE_OHCODEC] = "ohcodec",
94
};
95
96
typedef struct FFHWDeviceContext {
97
    /**
98
     * The public AVHWDeviceContext. See hwcontext.h for it.
99
     */
100
    AVHWDeviceContext p;
101
102
    const HWContextType *hw_type;
103
104
    /**
105
     * For a derived device, a reference to the original device
106
     * context it was derived from.
107
     */
108
    AVBufferRef *source_device;
109
} FFHWDeviceContext;
110
111
enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name)
112
0
{
113
0
    int type;
114
0
    for (type = 0; type < FF_ARRAY_ELEMS(hw_type_names); type++) {
115
0
        if (hw_type_names[type] && !strcmp(hw_type_names[type], name))
116
0
            return type;
117
0
    }
118
0
    return AV_HWDEVICE_TYPE_NONE;
119
0
}
120
121
const char *av_hwdevice_get_type_name(enum AVHWDeviceType type)
122
0
{
123
0
    if (type > AV_HWDEVICE_TYPE_NONE &&
124
0
        type < FF_ARRAY_ELEMS(hw_type_names))
125
0
        return hw_type_names[type];
126
0
    else
127
0
        return NULL;
128
0
}
129
130
enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev)
131
0
{
132
0
    enum AVHWDeviceType next;
133
0
    int i, set = 0;
134
0
    for (i = 0; hw_table[i]; i++) {
135
0
        if (prev != AV_HWDEVICE_TYPE_NONE && hw_table[i]->type <= prev)
136
0
            continue;
137
0
        if (!set || hw_table[i]->type < next) {
138
0
            next = hw_table[i]->type;
139
0
            set = 1;
140
0
        }
141
0
    }
142
0
    return set ? next : AV_HWDEVICE_TYPE_NONE;
143
0
}
144
145
static const char *hwdevice_ctx_get_name(void *ptr)
146
0
{
147
0
    FFHWDeviceContext *ctx = ptr;
148
0
    return ctx->hw_type->name;
149
0
}
150
151
static const AVClass hwdevice_ctx_class = {
152
    .class_name = "AVHWDeviceContext",
153
    .item_name  = hwdevice_ctx_get_name,
154
    .category   = AV_CLASS_CATEGORY_HWDEVICE,
155
    .version    = LIBAVUTIL_VERSION_INT,
156
};
157
158
static void hwdevice_ctx_free(void *opaque, uint8_t *data)
159
0
{
160
0
    FFHWDeviceContext *ctxi = (FFHWDeviceContext*)data;
161
0
    AVHWDeviceContext *ctx  = &ctxi->p;
162
163
    /* uninit might still want access the hw context and the user
164
     * free() callback might destroy it, so uninit has to be called first */
165
0
    if (ctxi->hw_type->device_uninit)
166
0
        ctxi->hw_type->device_uninit(ctx);
167
168
0
    if (ctx->free)
169
0
        ctx->free(ctx);
170
171
0
    av_buffer_unref(&ctxi->source_device);
172
173
0
    av_freep(&ctx->hwctx);
174
0
    av_freep(&ctx);
175
0
}
176
177
AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type)
178
0
{
179
0
    FFHWDeviceContext *ctxi;
180
0
    AVHWDeviceContext *ctx;
181
0
    AVBufferRef *buf;
182
0
    const HWContextType *hw_type = NULL;
183
0
    int i;
184
185
0
    for (i = 0; hw_table[i]; i++) {
186
0
        if (hw_table[i]->type == type) {
187
0
            hw_type = hw_table[i];
188
0
            break;
189
0
        }
190
0
    }
191
0
    if (!hw_type)
192
0
        return NULL;
193
194
0
    ctxi = av_mallocz(sizeof(*ctxi));
195
0
    if (!ctxi)
196
0
        return NULL;
197
0
    ctx = &ctxi->p;
198
199
0
    if (hw_type->device_hwctx_size) {
200
0
        ctx->hwctx = av_mallocz(hw_type->device_hwctx_size);
201
0
        if (!ctx->hwctx)
202
0
            goto fail;
203
0
    }
204
205
0
    buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx),
206
0
                           hwdevice_ctx_free, NULL,
207
0
                           AV_BUFFER_FLAG_READONLY);
208
0
    if (!buf)
209
0
        goto fail;
210
211
0
    ctx->type     = type;
212
0
    ctx->av_class = &hwdevice_ctx_class;
213
214
0
    ctxi->hw_type = hw_type;
215
216
0
    return buf;
217
218
0
fail:
219
0
    av_freep(&ctx->hwctx);
220
0
    av_freep(&ctx);
221
0
    return NULL;
222
0
}
223
224
int av_hwdevice_ctx_init(AVBufferRef *ref)
225
0
{
226
0
    FFHWDeviceContext *ctxi = (FFHWDeviceContext*)ref->data;
227
0
    AVHWDeviceContext *ctx  = &ctxi->p;
228
0
    int ret = 0;
229
230
0
    if (ctxi->hw_type->device_init)
231
0
        ret = ctxi->hw_type->device_init(ctx);
232
233
0
    return ret;
234
0
}
235
236
static const AVClass hwframe_ctx_class = {
237
    .class_name = "AVHWFramesContext",
238
    .item_name  = av_default_item_name,
239
    .version    = LIBAVUTIL_VERSION_INT,
240
};
241
242
static void hwframe_ctx_free(void *opaque, uint8_t *data)
243
0
{
244
0
    FFHWFramesContext *ctxi = (FFHWFramesContext*)data;
245
0
    AVHWFramesContext *ctx  = &ctxi->p;
246
247
0
    if (ctxi->pool_internal)
248
0
        av_buffer_pool_uninit(&ctxi->pool_internal);
249
250
0
    av_buffer_pool_uninit(&ctxi->transfer_pool);
251
0
    ff_mutex_destroy(&ctxi->transfer_pool_lock);
252
253
0
    if (ctxi->hw_type->frames_uninit)
254
0
        ctxi->hw_type->frames_uninit(ctx);
255
256
0
    if (ctx->free)
257
0
        ctx->free(ctx);
258
259
0
    av_buffer_unref(&ctxi->source_frames);
260
261
0
    av_buffer_unref(&ctx->device_ref);
262
263
0
    av_freep(&ctx->hwctx);
264
0
    av_freep(&ctx);
265
0
}
266
267
AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
268
0
{
269
0
    FFHWDeviceContext *device_ctx = (FFHWDeviceContext*)device_ref_in->data;
270
0
    const HWContextType  *hw_type = device_ctx->hw_type;
271
0
    FFHWFramesContext *ctxi;
272
0
    AVHWFramesContext *ctx;
273
0
    AVBufferRef *buf, *device_ref = NULL;
274
275
0
    ctxi = av_mallocz(sizeof(*ctxi));
276
0
    if (!ctxi)
277
0
        return NULL;
278
0
    ctx  = &ctxi->p;
279
280
0
    if (ff_mutex_init(&ctxi->transfer_pool_lock, NULL)) {
281
0
        av_free(ctxi);
282
0
        return NULL;
283
0
    }
284
285
0
    if (hw_type->frames_hwctx_size) {
286
0
        ctx->hwctx = av_mallocz(hw_type->frames_hwctx_size);
287
0
        if (!ctx->hwctx)
288
0
            goto fail;
289
0
    }
290
291
0
    device_ref = av_buffer_ref(device_ref_in);
292
0
    if (!device_ref)
293
0
        goto fail;
294
295
0
    buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx),
296
0
                           hwframe_ctx_free, NULL,
297
0
                           AV_BUFFER_FLAG_READONLY);
298
0
    if (!buf)
299
0
        goto fail;
300
301
0
    ctx->av_class   = &hwframe_ctx_class;
302
0
    ctx->device_ref = device_ref;
303
0
    ctx->device_ctx = &device_ctx->p;
304
0
    ctx->format     = AV_PIX_FMT_NONE;
305
0
    ctx->sw_format  = AV_PIX_FMT_NONE;
306
307
0
    ctxi->hw_type = hw_type;
308
309
0
    return buf;
310
311
0
fail:
312
0
    av_buffer_unref(&device_ref);
313
0
    ff_mutex_destroy(&ctxi->transfer_pool_lock);
314
0
    av_freep(&ctx->hwctx);
315
0
    av_freep(&ctx);
316
0
    return NULL;
317
0
}
318
319
static int hwframe_pool_prealloc(AVBufferRef *ref)
320
0
{
321
0
    AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data;
322
0
    AVFrame **frames;
323
0
    int i, ret = 0;
324
325
0
    frames = av_calloc(ctx->initial_pool_size, sizeof(*frames));
326
0
    if (!frames)
327
0
        return AVERROR(ENOMEM);
328
329
0
    for (i = 0; i < ctx->initial_pool_size; i++) {
330
0
        frames[i] = av_frame_alloc();
331
0
        if (!frames[i])
332
0
            goto fail;
333
334
0
        ret = av_hwframe_get_buffer(ref, frames[i], 0);
335
0
        if (ret < 0)
336
0
            goto fail;
337
0
    }
338
339
0
fail:
340
0
    for (i = 0; i < ctx->initial_pool_size; i++)
341
0
        av_frame_free(&frames[i]);
342
0
    av_freep(&frames);
343
344
0
    return ret;
345
0
}
346
347
int av_hwframe_ctx_init(AVBufferRef *ref)
348
0
{
349
0
    FFHWFramesContext *ctxi = (FFHWFramesContext*)ref->data;
350
0
    AVHWFramesContext *ctx  = &ctxi->p;
351
0
    const enum AVPixelFormat *pix_fmt;
352
0
    int ret;
353
354
0
    if (ctxi->source_frames) {
355
        /* A derived frame context is already initialised. */
356
0
        return 0;
357
0
    }
358
359
    /* validate the pixel format */
360
0
    for (pix_fmt = ctxi->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) {
361
0
        if (*pix_fmt == ctx->format)
362
0
            break;
363
0
    }
364
0
    if (*pix_fmt == AV_PIX_FMT_NONE) {
365
0
        av_log(ctx, AV_LOG_ERROR,
366
0
               "The hardware pixel format '%s' is not supported by the device type '%s'\n",
367
0
               av_get_pix_fmt_name(ctx->format), ctxi->hw_type->name);
368
0
        return AVERROR(ENOSYS);
369
0
    }
370
371
    /* validate the dimensions */
372
0
    ret = av_image_check_size(ctx->width, ctx->height, 0, ctx);
373
0
    if (ret < 0)
374
0
        return ret;
375
376
    /* format-specific init */
377
0
    if (ctxi->hw_type->frames_init) {
378
0
        ret = ctxi->hw_type->frames_init(ctx);
379
0
        if (ret < 0)
380
0
            return ret;
381
0
    }
382
383
0
    if (ctxi->pool_internal && !ctx->pool)
384
0
        ctx->pool = ctxi->pool_internal;
385
386
    /* preallocate the frames in the pool, if requested */
387
0
    if (ctx->initial_pool_size > 0) {
388
0
        ret = hwframe_pool_prealloc(ref);
389
0
        if (ret < 0)
390
0
            return ret;
391
0
    }
392
393
0
    return 0;
394
0
}
395
396
int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref,
397
                                    enum AVHWFrameTransferDirection dir,
398
                                    enum AVPixelFormat **formats, int flags)
399
0
{
400
0
    FFHWFramesContext *ctxi = (FFHWFramesContext*)hwframe_ref->data;
401
402
0
    if (!ctxi->hw_type->transfer_get_formats)
403
0
        return AVERROR(ENOSYS);
404
405
0
    return ctxi->hw_type->transfer_get_formats(&ctxi->p, dir, formats);
406
0
}
407
408
static void transfer_pool_free(void *opaque)
409
0
{
410
0
    AVBufferRef *device_ref = opaque;
411
0
    av_buffer_unref(&device_ref);
412
0
}
413
414
static AVBufferRef *transfer_buffer_alloc(void *opaque, size_t size)
415
0
{
416
0
    FFHWFramesContext *ctxi = opaque;
417
0
    AVBufferRef *buf = NULL;
418
419
0
    ff_mutex_lock(&ctxi->transfer_pool_lock);
420
0
    if (ctxi->transfer_pool_size != size) {
421
        /* buffers of the hardware context type need the device to be freed */
422
0
        AVBufferRef *device_ref = ctxi->hw_type->transfer_buffer_alloc ?
423
0
                                  av_buffer_ref(ctxi->p.device_ref) : NULL;
424
425
0
        av_buffer_pool_uninit(&ctxi->transfer_pool);
426
0
        ctxi->transfer_pool      = device_ref ?
427
0
            av_buffer_pool_init2(size, device_ref,
428
0
                                 ctxi->hw_type->transfer_buffer_alloc,
429
0
                                 transfer_pool_free) :
430
0
            av_buffer_pool_init(size, NULL);
431
0
        ctxi->transfer_pool_size = ctxi->transfer_pool ? size : 0;
432
0
        if (!ctxi->transfer_pool)
433
0
            av_buffer_unref(&device_ref);
434
0
    }
435
0
    if (ctxi->transfer_pool)
436
0
        buf = av_buffer_pool_get(ctxi->transfer_pool);
437
0
    ff_mutex_unlock(&ctxi->transfer_pool_lock);
438
439
0
    return buf ? buf : av_buffer_alloc(size);
440
0
}
441
442
int av_hwframe_get_transfer_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame)
443
0
{
444
0
    return ff_frame_get_video_buffer(frame, 0, transfer_buffer_alloc,
445
0
                                     hwframe_ctx->data);
446
0
}
447
448
static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags)
449
0
{
450
0
    AVHWFramesContext *ctx;
451
0
    AVFrame *frame_tmp;
452
0
    int ret = 0;
453
454
0
    if (!src->hw_frames_ctx)
455
0
        return AVERROR(EINVAL);
456
0
    ctx = (AVHWFramesContext*)src->hw_frames_ctx->data;
457
458
0
    frame_tmp = av_frame_alloc();
459
0
    if (!frame_tmp)
460
0
        return AVERROR(ENOMEM);
461
462
    /* if the format is set, use that
463
     * otherwise pick the first supported one */
464
0
    if (dst->format >= 0) {
465
0
        frame_tmp->format = dst->format;
466
0
    } else {
467
0
        enum AVPixelFormat *formats;
468
469
0
        ret = av_hwframe_transfer_get_formats(src->hw_frames_ctx,
470
0
                                              AV_HWFRAME_TRANSFER_DIRECTION_FROM,
471
0
                                              &formats, 0);
472
0
        if (ret < 0)
473
0
            goto fail;
474
0
        frame_tmp->format = formats[0];
475
0
        av_freep(&formats);
476
0
    }
477
0
    frame_tmp->width  = ctx->width;
478
0
    frame_tmp->height = ctx->height;
479
480
0
    ret = av_hwframe_get_transfer_buffer(src->hw_frames_ctx, frame_tmp);
481
0
    if (ret < 0)
482
0
        goto fail;
483
484
0
    ret = av_hwframe_transfer_data(frame_tmp, src, flags);
485
0
    if (ret < 0)
486
0
        goto fail;
487
488
0
    frame_tmp->width  = src->width;
489
0
    frame_tmp->height = src->height;
490
491
0
    av_frame_move_ref(dst, frame_tmp);
492
493
0
fail:
494
0
    av_frame_free(&frame_tmp);
495
0
    return ret;
496
0
}
497
498
int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags)
499
0
{
500
0
    int ret;
501
502
0
    if (!dst->buf[0])
503
0
        return transfer_data_alloc(dst, src, flags);
504
505
    /*
506
     * Hardware -> Hardware Transfer.
507
     * Unlike Software -> Hardware or Hardware -> Software, the transfer
508
     * function could be provided by either the src or dst, depending on
509
     * the specific combination of hardware.
510
     */
511
0
    if (src->hw_frames_ctx && dst->hw_frames_ctx) {
512
0
        FFHWFramesContext *src_ctx =
513
0
            (FFHWFramesContext*)src->hw_frames_ctx->data;
514
0
        FFHWFramesContext *dst_ctx =
515
0
            (FFHWFramesContext*)dst->hw_frames_ctx->data;
516
517
0
        if (src_ctx->source_frames) {
518
0
            av_log(src_ctx, AV_LOG_ERROR,
519
0
                   "A device with a derived frame context cannot be used as "
520
0
                   "the source of a HW -> HW transfer.");
521
0
            return AVERROR(ENOSYS);
522
0
        }
523
524
0
        if (dst_ctx->source_frames) {
525
0
            av_log(src_ctx, AV_LOG_ERROR,
526
0
                   "A device with a derived frame context cannot be used as "
527
0
                   "the destination of a HW -> HW transfer.");
528
0
            return AVERROR(ENOSYS);
529
0
        }
530
531
0
        ret = AVERROR(ENOSYS);
532
0
        if (src_ctx->hw_type->transfer_data_from)
533
0
            ret = src_ctx->hw_type->transfer_data_from(&src_ctx->p, dst, src);
534
0
        if (ret == AVERROR(ENOSYS) && dst_ctx->hw_type->transfer_data_to)
535
0
            ret = dst_ctx->hw_type->transfer_data_to(&dst_ctx->p, dst, src);
536
0
        if (ret < 0)
537
0
            return ret;
538
0
    } else {
539
0
        if (src->hw_frames_ctx) {
540
0
            FFHWFramesContext *ctx = (FFHWFramesContext*)src->hw_frames_ctx->data;
541
542
0
            if (!ctx->hw_type->transfer_data_from)
543
0
                return AVERROR(ENOSYS);
544
545
0
            ret = ctx->hw_type->transfer_data_from(&ctx->p, dst, src);
546
0
            if (ret < 0)
547
0
                return ret;
548
0
        } else if (dst->hw_frames_ctx) {
549
0
            FFHWFramesContext *ctx = (FFHWFramesContext*)dst->hw_frames_ctx->data;
550
551
0
            if (!ctx->hw_type->transfer_data_to)
552
0
                return AVERROR(ENOSYS);
553
554
0
            ret = ctx->hw_type->transfer_data_to(&ctx->p, dst, src);
555
0
            if (ret < 0)
556
0
                return ret;
557
0
        } else {
558
0
            return AVERROR(ENOSYS);
559
0
        }
560
0
    }
561
0
    return 0;
562
0
}
563
564
int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags)
565
0
{
566
0
    FFHWFramesContext *ctxi = (FFHWFramesContext*)hwframe_ref->data;
567
0
    AVHWFramesContext *ctx  = &ctxi->p;
568
0
    int ret;
569
570
0
    if (ctxi->source_frames) {
571
        // This is a derived frame context, so we allocate in the source
572
        // and map the frame immediately.
573
0
        AVFrame *src_frame;
574
575
0
        frame->format = ctx->format;
576
0
        frame->hw_frames_ctx = av_buffer_ref(hwframe_ref);
577
0
        if (!frame->hw_frames_ctx)
578
0
            return AVERROR(ENOMEM);
579
580
0
        src_frame = av_frame_alloc();
581
0
        if (!src_frame)
582
0
            return AVERROR(ENOMEM);
583
584
0
        ret = av_hwframe_get_buffer(ctxi->source_frames,
585
0
                                    src_frame, 0);
586
0
        if (ret < 0) {
587
0
            av_frame_free(&src_frame);
588
0
            return ret;
589
0
        }
590
591
0
        ret = av_hwframe_map(frame, src_frame,
592
0
                             ctxi->source_allocation_map_flags);
593
0
        if (ret) {
594
0
            av_log(ctx, AV_LOG_ERROR, "Failed to map frame into derived "
595
0
                   "frame context: %d.\n", ret);
596
0
            av_frame_free(&src_frame);
597
0
            return ret;
598
0
        }
599
600
        // Free the source frame immediately - the mapped frame still
601
        // contains a reference to it.
602
0
        av_frame_free(&src_frame);
603
604
0
        return 0;
605
0
    }
606
607
0
    if (!ctxi->hw_type->frames_get_buffer)
608
0
        return AVERROR(ENOSYS);
609
610
0
    if (!ctx->pool)
611
0
        return AVERROR(EINVAL);
612
613
0
    frame->hw_frames_ctx = av_buffer_ref(hwframe_ref);
614
0
    if (!frame->hw_frames_ctx)
615
0
        return AVERROR(ENOMEM);
616
617
0
    ret = ctxi->hw_type->frames_get_buffer(ctx, frame);
618
0
    if (ret < 0) {
619
0
        av_buffer_unref(&frame->hw_frames_ctx);
620
0
        return ret;
621
0
    }
622
623
0
    frame->extended_data = frame->data;
624
625
0
    return 0;
626
0
}
627
628
void *av_hwdevice_hwconfig_alloc(AVBufferRef *ref)
629
0
{
630
0
    FFHWDeviceContext *ctx = (FFHWDeviceContext*)ref->data;
631
0
    const HWContextType  *hw_type = ctx->hw_type;
632
633
0
    if (hw_type->device_hwconfig_size == 0)
634
0
        return NULL;
635
636
0
    return av_mallocz(hw_type->device_hwconfig_size);
637
0
}
638
639
AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref,
640
                                                           const void *hwconfig)
641
0
{
642
0
    FFHWDeviceContext *ctx = (FFHWDeviceContext*)ref->data;
643
0
    const HWContextType  *hw_type = ctx->hw_type;
644
0
    AVHWFramesConstraints *constraints;
645
646
0
    if (!hw_type->frames_get_constraints)
647
0
        return NULL;
648
649
0
    constraints = av_mallocz(sizeof(*constraints));
650
0
    if (!constraints)
651
0
        return NULL;
652
653
0
    constraints->min_width = constraints->min_height = 0;
654
0
    constraints->max_width = constraints->max_height = INT_MAX;
655
656
0
    if (hw_type->frames_get_constraints(&ctx->p, hwconfig, constraints) >= 0) {
657
0
        return constraints;
658
0
    } else {
659
0
        av_hwframe_constraints_free(&constraints);
660
0
        return NULL;
661
0
    }
662
0
}
663
664
void av_hwframe_constraints_free(AVHWFramesConstraints **constraints)
665
0
{
666
0
    if (*constraints) {
667
0
        av_freep(&(*constraints)->valid_hw_formats);
668
0
        av_freep(&(*constraints)->valid_sw_formats);
669
0
    }
670
0
    av_freep(constraints);
671
0
}
672
673
int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type,
674
                           const char *device, AVDictionary *opts, int flags)
675
0
{
676
0
    AVBufferRef *device_ref = NULL;
677
0
    FFHWDeviceContext *device_ctx;
678
0
    int ret = 0;
679
680
0
    device_ref = av_hwdevice_ctx_alloc(type);
681
0
    if (!device_ref) {
682
0
        ret = AVERROR(ENOMEM);
683
0
        goto fail;
684
0
    }
685
0
    device_ctx = (FFHWDeviceContext*)device_ref->data;
686
687
0
    if (!device_ctx->hw_type->device_create) {
688
0
        ret = AVERROR(ENOSYS);
689
0
        goto fail;
690
0
    }
691
692
0
    ret = device_ctx->hw_type->device_create(&device_ctx->p, device,
693
0
                                             opts, flags);
694
0
    if (ret < 0)
695
0
        goto fail;
696
697
0
    ret = av_hwdevice_ctx_init(device_ref);
698
0
    if (ret < 0)
699
0
        goto fail;
700
701
0
    *pdevice_ref = device_ref;
702
0
    return 0;
703
0
fail:
704
0
    av_buffer_unref(&device_ref);
705
0
    *pdevice_ref = NULL;
706
0
    return ret;
707
0
}
708
709
int av_hwdevice_ctx_create_derived_opts(AVBufferRef **dst_ref_ptr,
710
                                        enum AVHWDeviceType type,
711
                                        AVBufferRef *src_ref,
712
                                        AVDictionary *options, int flags)
713
0
{
714
0
    AVBufferRef *dst_ref = NULL, *tmp_ref;
715
0
    FFHWDeviceContext *dst_ctx;
716
0
    int ret = 0;
717
718
0
    tmp_ref = src_ref;
719
0
    while (tmp_ref) {
720
0
        FFHWDeviceContext *tmp_ctx = (FFHWDeviceContext*)tmp_ref->data;
721
0
        if (tmp_ctx->p.type == type) {
722
0
            dst_ref = av_buffer_ref(tmp_ref);
723
0
            if (!dst_ref) {
724
0
                ret = AVERROR(ENOMEM);
725
0
                goto fail;
726
0
            }
727
0
            goto done;
728
0
        }
729
0
        tmp_ref = tmp_ctx->source_device;
730
0
    }
731
732
0
    dst_ref = av_hwdevice_ctx_alloc(type);
733
0
    if (!dst_ref) {
734
0
        ret = AVERROR(ENOMEM);
735
0
        goto fail;
736
0
    }
737
0
    dst_ctx = (FFHWDeviceContext*)dst_ref->data;
738
739
0
    tmp_ref = src_ref;
740
0
    while (tmp_ref) {
741
0
        FFHWDeviceContext *tmp_ctx = (FFHWDeviceContext*)tmp_ref->data;
742
0
        if (dst_ctx->hw_type->device_derive) {
743
0
            ret = dst_ctx->hw_type->device_derive(&dst_ctx->p,
744
0
                                                  &tmp_ctx->p,
745
0
                                                  options, flags);
746
0
            if (ret == 0) {
747
0
                dst_ctx->source_device = av_buffer_ref(src_ref);
748
0
                if (!dst_ctx->source_device) {
749
0
                    ret = AVERROR(ENOMEM);
750
0
                    goto fail;
751
0
                }
752
0
                ret = av_hwdevice_ctx_init(dst_ref);
753
0
                if (ret < 0)
754
0
                    goto fail;
755
0
                goto done;
756
0
            }
757
0
            if (ret != AVERROR(ENOSYS))
758
0
                goto fail;
759
0
        }
760
0
        tmp_ref = tmp_ctx->source_device;
761
0
    }
762
763
0
    ret = AVERROR(ENOSYS);
764
0
    goto fail;
765
766
0
done:
767
0
    *dst_ref_ptr = dst_ref;
768
0
    return 0;
769
770
0
fail:
771
0
    av_buffer_unref(&dst_ref);
772
0
    *dst_ref_ptr = NULL;
773
0
    return ret;
774
0
}
775
776
int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr,
777
                                   enum AVHWDeviceType type,
778
                                   AVBufferRef *src_ref, int flags)
779
0
{
780
0
    return av_hwdevice_ctx_create_derived_opts(dst_ref_ptr, type, src_ref,
781
0
                                               NULL, flags);
782
0
}
783
784
static void ff_hwframe_unmap(void *opaque, uint8_t *data)
785
0
{
786
0
    HWMapDescriptor *hwmap = (HWMapDescriptor*)data;
787
0
    AVHWFramesContext *ctx = opaque;
788
789
0
    if (hwmap->unmap)
790
0
        hwmap->unmap(ctx, hwmap);
791
792
0
    av_frame_free(&hwmap->source);
793
794
0
    av_buffer_unref(&hwmap->hw_frames_ctx);
795
796
0
    av_free(hwmap);
797
0
}
798
799
int ff_hwframe_map_create(AVBufferRef *hwframe_ref,
800
                          AVFrame *dst, const AVFrame *src,
801
                          void (*unmap)(AVHWFramesContext *ctx,
802
                                        HWMapDescriptor *hwmap),
803
                          void *priv)
804
0
{
805
0
    AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data;
806
0
    HWMapDescriptor *hwmap;
807
0
    int ret;
808
809
0
    hwmap = av_mallocz(sizeof(*hwmap));
810
0
    if (!hwmap) {
811
0
        ret = AVERROR(ENOMEM);
812
0
        goto fail;
813
0
    }
814
815
0
    hwmap->source = av_frame_alloc();
816
0
    if (!hwmap->source) {
817
0
        ret = AVERROR(ENOMEM);
818
0
        goto fail;
819
0
    }
820
0
    ret = av_frame_ref(hwmap->source, src);
821
0
    if (ret < 0)
822
0
        goto fail;
823
824
0
    hwmap->hw_frames_ctx = av_buffer_ref(hwframe_ref);
825
0
    if (!hwmap->hw_frames_ctx) {
826
0
        ret = AVERROR(ENOMEM);
827
0
        goto fail;
828
0
    }
829
830
0
    hwmap->unmap = unmap;
831
0
    hwmap->priv  = priv;
832
833
0
    dst->buf[0] = av_buffer_create((uint8_t*)hwmap, sizeof(*hwmap),
834
0
                                   &ff_hwframe_unmap, ctx, 0);
835
0
    if (!dst->buf[0]) {
836
0
        ret = AVERROR(ENOMEM);
837
0
        goto fail;
838
0
    }
839
840
0
    return 0;
841
842
0
fail:
843
0
    if (hwmap) {
844
0
        av_buffer_unref(&hwmap->hw_frames_ctx);
845
0
        av_frame_free(&hwmap->source);
846
0
    }
847
0
    av_free(hwmap);
848
0
    return ret;
849
0
}
850
851
int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
852
0
{
853
0
    AVBufferRef    *orig_dst_frames = dst->hw_frames_ctx;
854
0
    enum AVPixelFormat orig_dst_fmt = dst->format;
855
0
    HWMapDescriptor *hwmap;
856
0
    int ret;
857
858
0
    if (src->hw_frames_ctx && dst->hw_frames_ctx) {
859
0
        FFHWFramesContext *src_frames = (FFHWFramesContext*)src->hw_frames_ctx->data;
860
0
        FFHWFramesContext *dst_frames = (FFHWFramesContext*)dst->hw_frames_ctx->data;
861
862
0
        if ((src_frames == dst_frames &&
863
0
             src->format == dst_frames->p.sw_format &&
864
0
             dst->format == dst_frames->p.format) ||
865
0
            (src_frames->source_frames &&
866
0
             src_frames->source_frames->data ==
867
0
             (uint8_t*)dst_frames)) {
868
            // This is an unmap operation.  We don't need to directly
869
            // do anything here other than fill in the original frame,
870
            // because the real unmap will be invoked when the last
871
            // reference to the mapped frame disappears.
872
0
            if (!src->buf[0]) {
873
0
                av_log(src_frames, AV_LOG_ERROR, "Invalid mapping "
874
0
                       "found when attempting unmap.\n");
875
0
                return AVERROR(EINVAL);
876
0
            }
877
0
            hwmap = (HWMapDescriptor*)src->buf[0]->data;
878
0
            return av_frame_replace(dst, hwmap->source);
879
0
        }
880
0
    }
881
882
0
    if (src->hw_frames_ctx) {
883
0
        FFHWFramesContext *src_frames = (FFHWFramesContext*)src->hw_frames_ctx->data;
884
885
0
        if (src_frames->p.format == src->format &&
886
0
            src_frames->hw_type->map_from) {
887
0
            ret = src_frames->hw_type->map_from(&src_frames->p,
888
0
                                                dst, src, flags);
889
0
            if (ret >= 0)
890
0
                return ret;
891
0
            else if (ret != AVERROR(ENOSYS))
892
0
                goto fail;
893
0
        }
894
0
    }
895
896
0
    if (dst->hw_frames_ctx) {
897
0
        FFHWFramesContext *dst_frames = (FFHWFramesContext*)dst->hw_frames_ctx->data;
898
899
0
        if (dst_frames->p.format == dst->format &&
900
0
            dst_frames->hw_type->map_to) {
901
0
            ret = dst_frames->hw_type->map_to(&dst_frames->p,
902
0
                                              dst, src, flags);
903
0
            if (ret >= 0)
904
0
                return ret;
905
0
            else if (ret != AVERROR(ENOSYS))
906
0
                goto fail;
907
0
        }
908
0
    }
909
910
0
    return AVERROR(ENOSYS);
911
912
0
fail:
913
    // if the caller provided dst frames context, it should be preserved
914
    // by this function
915
0
    av_assert0(orig_dst_frames == NULL ||
916
0
               orig_dst_frames == dst->hw_frames_ctx);
917
918
    // preserve user-provided dst frame fields, but clean
919
    // anything we might have set
920
0
    dst->hw_frames_ctx = NULL;
921
0
    av_frame_unref(dst);
922
923
0
    dst->hw_frames_ctx = orig_dst_frames;
924
0
    dst->format        = orig_dst_fmt;
925
926
0
    return ret;
927
0
}
928
929
int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx,
930
                                  enum AVPixelFormat format,
931
                                  AVBufferRef *derived_device_ctx,
932
                                  AVBufferRef *source_frame_ctx,
933
                                  int flags)
934
0
{
935
0
    AVBufferRef   *dst_ref = NULL;
936
0
    FFHWFramesContext *dsti = NULL;
937
0
    FFHWFramesContext *srci = (FFHWFramesContext*)source_frame_ctx->data;
938
0
    AVHWFramesContext *dst, *src = &srci->p;
939
0
    int ret;
940
941
0
    if (srci->source_frames) {
942
0
        AVHWFramesContext *src_src =
943
0
            (AVHWFramesContext*)srci->source_frames->data;
944
0
        AVHWDeviceContext *dst_dev =
945
0
            (AVHWDeviceContext*)derived_device_ctx->data;
946
947
0
        if (src_src->device_ctx == dst_dev) {
948
            // This is actually an unmapping, so we just return a
949
            // reference to the source frame context.
950
0
            *derived_frame_ctx = av_buffer_ref(srci->source_frames);
951
0
            if (!*derived_frame_ctx) {
952
0
                ret = AVERROR(ENOMEM);
953
0
                goto fail;
954
0
            }
955
0
            return 0;
956
0
        }
957
0
    }
958
959
0
    dst_ref = av_hwframe_ctx_alloc(derived_device_ctx);
960
0
    if (!dst_ref) {
961
0
        ret = AVERROR(ENOMEM);
962
0
        goto fail;
963
0
    }
964
965
0
    dsti = (FFHWFramesContext*)dst_ref->data;
966
0
    dst  = &dsti->p;
967
968
0
    dst->format    = format;
969
0
    dst->sw_format = src->sw_format;
970
0
    dst->width     = src->width;
971
0
    dst->height    = src->height;
972
973
0
    dsti->source_frames = av_buffer_ref(source_frame_ctx);
974
0
    if (!dsti->source_frames) {
975
0
        ret = AVERROR(ENOMEM);
976
0
        goto fail;
977
0
    }
978
979
0
    dsti->source_allocation_map_flags =
980
0
        flags & (AV_HWFRAME_MAP_READ      |
981
0
                 AV_HWFRAME_MAP_WRITE     |
982
0
                 AV_HWFRAME_MAP_OVERWRITE |
983
0
                 AV_HWFRAME_MAP_DIRECT);
984
985
0
    ret = AVERROR(ENOSYS);
986
0
    if (srci->hw_type->frames_derive_from)
987
0
        ret = srci->hw_type->frames_derive_from(dst, src, flags);
988
0
    if (ret == AVERROR(ENOSYS) &&
989
0
        dsti->hw_type->frames_derive_to)
990
0
        ret = dsti->hw_type->frames_derive_to(dst, src, flags);
991
0
    if (ret == AVERROR(ENOSYS))
992
0
        ret = 0;
993
0
    if (ret)
994
0
        goto fail;
995
996
0
    *derived_frame_ctx = dst_ref;
997
0
    return 0;
998
999
0
fail:
1000
0
    if (dsti)
1001
0
        av_buffer_unref(&dsti->source_frames);
1002
0
    av_buffer_unref(&dst_ref);
1003
0
    return ret;
1004
0
}
1005
1006
int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src)
1007
0
{
1008
0
    HWMapDescriptor *hwmap = (HWMapDescriptor*)dst->buf[0]->data;
1009
0
    return av_frame_replace(hwmap->source, src);
1010
0
}