Dmitrii Ovchinnikovavutil: add hwcontext_amf.9e724252 years agoHistory
941 lines · 25.9 KB · C
RawDownload
/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include "avassert.h"#include "buffer.h"#include "common.h"#include "hwcontext.h"#include "hwcontext_internal.h"#include "imgutils.h"#include "log.h"#include "mem.h"#include "pixdesc.h"#include "pixfmt.h" static const HWContextType * const hw_table[] = {#if CONFIG_CUDA    &ff_hwcontext_type_cuda,#endif#if CONFIG_D3D11VA    &ff_hwcontext_type_d3d11va,#endif#if CONFIG_D3D12VA    &ff_hwcontext_type_d3d12va,#endif#if CONFIG_LIBDRM    &ff_hwcontext_type_drm,#endif#if CONFIG_DXVA2    &ff_hwcontext_type_dxva2,#endif#if CONFIG_OPENCL    &ff_hwcontext_type_opencl,#endif#if CONFIG_QSV    &ff_hwcontext_type_qsv,#endif#if CONFIG_VAAPI    &ff_hwcontext_type_vaapi,#endif#if CONFIG_VDPAU    &ff_hwcontext_type_vdpau,#endif#if CONFIG_VIDEOTOOLBOX    &ff_hwcontext_type_videotoolbox,#endif#if CONFIG_MEDIACODEC    &ff_hwcontext_type_mediacodec,#endif#if CONFIG_VULKAN    &ff_hwcontext_type_vulkan,#endif#if CONFIG_AMF    &ff_hwcontext_type_amf,#endif    NULL,}; static const char *const hw_type_names[] = {    [AV_HWDEVICE_TYPE_CUDA]   = "cuda",    [AV_HWDEVICE_TYPE_DRM]    = "drm",    [AV_HWDEVICE_TYPE_DXVA2]  = "dxva2",    [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va",    [AV_HWDEVICE_TYPE_D3D12VA] = "d3d12va",    [AV_HWDEVICE_TYPE_OPENCL] = "opencl",    [AV_HWDEVICE_TYPE_QSV]    = "qsv",    [AV_HWDEVICE_TYPE_VAAPI]  = "vaapi",    [AV_HWDEVICE_TYPE_VDPAU]  = "vdpau",    [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",    [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",    [AV_HWDEVICE_TYPE_VULKAN] = "vulkan",    [AV_HWDEVICE_TYPE_AMF] = "amf",}; typedef struct FFHWDeviceContext {    /**     * The public AVHWDeviceContext. See hwcontext.h for it.     */    AVHWDeviceContext p;     const HWContextType *hw_type;     /**     * For a derived device, a reference to the original device     * context it was derived from.     */    AVBufferRef *source_device;} FFHWDeviceContext; enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name){    int type;    for (type = 0; type < FF_ARRAY_ELEMS(hw_type_names); type++) {        if (hw_type_names[type] && !strcmp(hw_type_names[type], name))            return type;    }    return AV_HWDEVICE_TYPE_NONE;} const char *av_hwdevice_get_type_name(enum AVHWDeviceType type){    if (type > AV_HWDEVICE_TYPE_NONE &&        type < FF_ARRAY_ELEMS(hw_type_names))        return hw_type_names[type];    else        return NULL;} enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev){    enum AVHWDeviceType next;    int i, set = 0;    for (i = 0; hw_table[i]; i++) {        if (prev != AV_HWDEVICE_TYPE_NONE && hw_table[i]->type <= prev)            continue;        if (!set || hw_table[i]->type < next) {            next = hw_table[i]->type;            set = 1;        }    }    return set ? next : AV_HWDEVICE_TYPE_NONE;} static const AVClass hwdevice_ctx_class = {    .class_name = "AVHWDeviceContext",    .item_name  = av_default_item_name,    .version    = LIBAVUTIL_VERSION_INT,}; static void hwdevice_ctx_free(void *opaque, uint8_t *data){    FFHWDeviceContext *ctxi = (FFHWDeviceContext*)data;    AVHWDeviceContext *ctx  = &ctxi->p;     /* uninit might still want access the hw context and the user     * free() callback might destroy it, so uninit has to be called first */    if (ctxi->hw_type->device_uninit)        ctxi->hw_type->device_uninit(ctx);     if (ctx->free)        ctx->free(ctx);     av_buffer_unref(&ctxi->source_device);     av_freep(&ctx->hwctx);    av_freep(&ctx);} AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type){    FFHWDeviceContext *ctxi;    AVHWDeviceContext *ctx;    AVBufferRef *buf;    const HWContextType *hw_type = NULL;    int i;     for (i = 0; hw_table[i]; i++) {        if (hw_table[i]->type == type) {            hw_type = hw_table[i];            break;        }    }    if (!hw_type)        return NULL;     ctxi = av_mallocz(sizeof(*ctxi));    if (!ctxi)        return NULL;    ctx = &ctxi->p;     if (hw_type->device_hwctx_size) {        ctx->hwctx = av_mallocz(hw_type->device_hwctx_size);        if (!ctx->hwctx)            goto fail;    }     buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx),                           hwdevice_ctx_free, NULL,                           AV_BUFFER_FLAG_READONLY);    if (!buf)        goto fail;     ctx->type     = type;    ctx->av_class = &hwdevice_ctx_class;     ctxi->hw_type = hw_type;     return buf; fail:    av_freep(&ctx->hwctx);    av_freep(&ctx);    return NULL;} int av_hwdevice_ctx_init(AVBufferRef *ref){    FFHWDeviceContext *ctxi = (FFHWDeviceContext*)ref->data;    AVHWDeviceContext *ctx  = &ctxi->p;    int ret = 0;     if (ctxi->hw_type->device_init)        ret = ctxi->hw_type->device_init(ctx);     return ret;} static const AVClass hwframe_ctx_class = {    .class_name = "AVHWFramesContext",    .item_name  = av_default_item_name,    .version    = LIBAVUTIL_VERSION_INT,}; static void hwframe_ctx_free(void *opaque, uint8_t *data){    FFHWFramesContext *ctxi = (FFHWFramesContext*)data;    AVHWFramesContext *ctx  = &ctxi->p;     if (ctxi->pool_internal)        av_buffer_pool_uninit(&ctxi->pool_internal);     if (ctxi->hw_type->frames_uninit)        ctxi->hw_type->frames_uninit(ctx);     if (ctx->free)        ctx->free(ctx);     av_buffer_unref(&ctxi->source_frames);     av_buffer_unref(&ctx->device_ref);     av_freep(&ctx->hwctx);    av_freep(&ctx);} AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in){    FFHWDeviceContext *device_ctx = (FFHWDeviceContext*)device_ref_in->data;    const HWContextType  *hw_type = device_ctx->hw_type;    FFHWFramesContext *ctxi;    AVHWFramesContext *ctx;    AVBufferRef *buf, *device_ref = NULL;     ctxi = av_mallocz(sizeof(*ctxi));    if (!ctxi)        return NULL;    ctx  = &ctxi->p;     if (hw_type->frames_hwctx_size) {        ctx->hwctx = av_mallocz(hw_type->frames_hwctx_size);        if (!ctx->hwctx)            goto fail;    }     device_ref = av_buffer_ref(device_ref_in);    if (!device_ref)        goto fail;     buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx),                           hwframe_ctx_free, NULL,                           AV_BUFFER_FLAG_READONLY);    if (!buf)        goto fail;     ctx->av_class   = &hwframe_ctx_class;    ctx->device_ref = device_ref;    ctx->device_ctx = &device_ctx->p;    ctx->format     = AV_PIX_FMT_NONE;    ctx->sw_format  = AV_PIX_FMT_NONE;     ctxi->hw_type = hw_type;     return buf; fail:    av_buffer_unref(&device_ref);    av_freep(&ctx->hwctx);    av_freep(&ctx);    return NULL;} static int hwframe_pool_prealloc(AVBufferRef *ref){    AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data;    AVFrame **frames;    int i, ret = 0;     frames = av_calloc(ctx->initial_pool_size, sizeof(*frames));    if (!frames)        return AVERROR(ENOMEM);     for (i = 0; i < ctx->initial_pool_size; i++) {        frames[i] = av_frame_alloc();        if (!frames[i])            goto fail;         ret = av_hwframe_get_buffer(ref, frames[i], 0);        if (ret < 0)            goto fail;    } fail:    for (i = 0; i < ctx->initial_pool_size; i++)        av_frame_free(&frames[i]);    av_freep(&frames);     return ret;} int av_hwframe_ctx_init(AVBufferRef *ref){    FFHWFramesContext *ctxi = (FFHWFramesContext*)ref->data;    AVHWFramesContext *ctx  = &ctxi->p;    const enum AVPixelFormat *pix_fmt;    int ret;     if (ctxi->source_frames) {        /* A derived frame context is already initialised. */        return 0;    }     /* validate the pixel format */    for (pix_fmt = ctxi->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) {        if (*pix_fmt == ctx->format)            break;    }    if (*pix_fmt == AV_PIX_FMT_NONE) {        av_log(ctx, AV_LOG_ERROR,               "The hardware pixel format '%s' is not supported by the device type '%s'\n",               av_get_pix_fmt_name(ctx->format), ctxi->hw_type->name);        return AVERROR(ENOSYS);    }     /* validate the dimensions */    ret = av_image_check_size(ctx->width, ctx->height, 0, ctx);    if (ret < 0)        return ret;     /* format-specific init */    if (ctxi->hw_type->frames_init) {        ret = ctxi->hw_type->frames_init(ctx);        if (ret < 0)            return ret;    }     if (ctxi->pool_internal && !ctx->pool)        ctx->pool = ctxi->pool_internal;     /* preallocate the frames in the pool, if requested */    if (ctx->initial_pool_size > 0) {        ret = hwframe_pool_prealloc(ref);        if (ret < 0)            return ret;    }     return 0;} int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref,                                    enum AVHWFrameTransferDirection dir,                                    enum AVPixelFormat **formats, int flags){    FFHWFramesContext *ctxi = (FFHWFramesContext*)hwframe_ref->data;     if (!ctxi->hw_type->transfer_get_formats)        return AVERROR(ENOSYS);     return ctxi->hw_type->transfer_get_formats(&ctxi->p, dir, formats);} static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags){    AVHWFramesContext *ctx;    AVFrame *frame_tmp;    int ret = 0;     if (!src->hw_frames_ctx)        return AVERROR(EINVAL);    ctx = (AVHWFramesContext*)src->hw_frames_ctx->data;     frame_tmp = av_frame_alloc();    if (!frame_tmp)        return AVERROR(ENOMEM);     /* if the format is set, use that     * otherwise pick the first supported one */    if (dst->format >= 0) {        frame_tmp->format = dst->format;    } else {        enum AVPixelFormat *formats;         ret = av_hwframe_transfer_get_formats(src->hw_frames_ctx,                                              AV_HWFRAME_TRANSFER_DIRECTION_FROM,                                              &formats, 0);        if (ret < 0)            goto fail;        frame_tmp->format = formats[0];        av_freep(&formats);    }    frame_tmp->width  = ctx->width;    frame_tmp->height = ctx->height;     ret = av_frame_get_buffer(frame_tmp, 0);    if (ret < 0)        goto fail;     ret = av_hwframe_transfer_data(frame_tmp, src, flags);    if (ret < 0)        goto fail;     frame_tmp->width  = src->width;    frame_tmp->height = src->height;     av_frame_move_ref(dst, frame_tmp); fail:    av_frame_free(&frame_tmp);    return ret;} int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags){    int ret;     if (!dst->buf[0])        return transfer_data_alloc(dst, src, flags);     /*     * Hardware -> Hardware Transfer.     * Unlike Software -> Hardware or Hardware -> Software, the transfer     * function could be provided by either the src or dst, depending on     * the specific combination of hardware.     */    if (src->hw_frames_ctx && dst->hw_frames_ctx) {        FFHWFramesContext *src_ctx =            (FFHWFramesContext*)src->hw_frames_ctx->data;        FFHWFramesContext *dst_ctx =            (FFHWFramesContext*)dst->hw_frames_ctx->data;         if (src_ctx->source_frames) {            av_log(src_ctx, AV_LOG_ERROR,                   "A device with a derived frame context cannot be used as "                   "the source of a HW -> HW transfer.");            return AVERROR(ENOSYS);        }         if (dst_ctx->source_frames) {            av_log(src_ctx, AV_LOG_ERROR,                   "A device with a derived frame context cannot be used as "                   "the destination of a HW -> HW transfer.");            return AVERROR(ENOSYS);        }         ret = src_ctx->hw_type->transfer_data_from(&src_ctx->p, dst, src);        if (ret == AVERROR(ENOSYS))            ret = dst_ctx->hw_type->transfer_data_to(&dst_ctx->p, dst, src);        if (ret < 0)            return ret;    } else {        if (src->hw_frames_ctx) {            FFHWFramesContext *ctx = (FFHWFramesContext*)src->hw_frames_ctx->data;             ret = ctx->hw_type->transfer_data_from(&ctx->p, dst, src);            if (ret < 0)                return ret;        } else if (dst->hw_frames_ctx) {            FFHWFramesContext *ctx = (FFHWFramesContext*)dst->hw_frames_ctx->data;             ret = ctx->hw_type->transfer_data_to(&ctx->p, dst, src);            if (ret < 0)                return ret;        } else {            return AVERROR(ENOSYS);        }    }    return 0;} int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags){    FFHWFramesContext *ctxi = (FFHWFramesContext*)hwframe_ref->data;    AVHWFramesContext *ctx  = &ctxi->p;    int ret; 

Lines 1–500 of 941.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t