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