* commit '89923e418b494e337683442ab896d754bc07341a': lavu: add a framework for handling hwaccel frames Merged-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>tags/n3.1
| @@ -17,6 +17,8 @@ API changes, most recent first: | |||
| 2016-xx-xx - lavu 55.18.0 | |||
| xxxxxxx buffer.h - Add av_buffer_pool_init2(). | |||
| xxxxxxx hwcontext.h - Add a new installed header hwcontext.h with a new API | |||
| for handling hwaccel frames. | |||
| -------- 8< --------- FFmpeg 3.0 was cut here -------- 8< --------- | |||
| @@ -31,6 +31,7 @@ HEADERS = adler32.h \ | |||
| frame.h \ | |||
| hash.h \ | |||
| hmac.h \ | |||
| hwcontext.h \ | |||
| imgutils.h \ | |||
| intfloat.h \ | |||
| intreadwrite.h \ | |||
| @@ -108,6 +109,7 @@ OBJS = adler32.o \ | |||
| frame.o \ | |||
| hash.o \ | |||
| hmac.o \ | |||
| hwcontext.o \ | |||
| imgutils.o \ | |||
| integer.o \ | |||
| intmath.o \ | |||
| @@ -429,6 +429,14 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src) | |||
| } | |||
| } | |||
| if (src->hw_frames_ctx) { | |||
| dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx); | |||
| if (!dst->hw_frames_ctx) { | |||
| ret = AVERROR(ENOMEM); | |||
| goto fail; | |||
| } | |||
| } | |||
| /* duplicate extended data */ | |||
| if (src->extended_data != src->data) { | |||
| int ch = src->channels; | |||
| @@ -490,6 +498,8 @@ void av_frame_unref(AVFrame *frame) | |||
| av_buffer_unref(&frame->qp_table_buf); | |||
| #endif | |||
| av_buffer_unref(&frame->hw_frames_ctx); | |||
| get_frame_defaults(frame); | |||
| } | |||
| @@ -421,6 +421,12 @@ typedef struct AVFrame { | |||
| enum AVChromaLocation chroma_location; | |||
| /** | |||
| * For hwaccel-format frames, this should be a reference to the | |||
| * AVHWFramesContext describing the frame. | |||
| */ | |||
| AVBufferRef *hw_frames_ctx; | |||
| /** | |||
| * frame timestamp estimated using various heuristics, in stream time base | |||
| * Code outside libavutil should access this field using: | |||
| @@ -0,0 +1,396 @@ | |||
| /* | |||
| * 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 "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 *hw_table[] = { | |||
| NULL, | |||
| }; | |||
| 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) | |||
| { | |||
| AVHWDeviceContext *ctx = (AVHWDeviceContext*)data; | |||
| /* uninit might still want access the hw context and the user | |||
| * free() callback might destroy it, so uninit has to be called first */ | |||
| if (ctx->internal->hw_type->device_uninit) | |||
| ctx->internal->hw_type->device_uninit(ctx); | |||
| if (ctx->free) | |||
| ctx->free(ctx); | |||
| av_freep(&ctx->hwctx); | |||
| av_freep(&ctx->internal->priv); | |||
| av_freep(&ctx->internal); | |||
| av_freep(&ctx); | |||
| } | |||
| AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type) | |||
| { | |||
| 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; | |||
| ctx = av_mallocz(sizeof(*ctx)); | |||
| if (!ctx) | |||
| return NULL; | |||
| ctx->internal = av_mallocz(sizeof(*ctx->internal)); | |||
| if (!ctx->internal) | |||
| goto fail; | |||
| if (hw_type->device_priv_size) { | |||
| ctx->internal->priv = av_mallocz(hw_type->device_priv_size); | |||
| if (!ctx->internal->priv) | |||
| goto fail; | |||
| } | |||
| 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; | |||
| ctx->internal->hw_type = hw_type; | |||
| return buf; | |||
| fail: | |||
| if (ctx->internal) | |||
| av_freep(&ctx->internal->priv); | |||
| av_freep(&ctx->internal); | |||
| av_freep(&ctx->hwctx); | |||
| av_freep(&ctx); | |||
| return NULL; | |||
| } | |||
| int av_hwdevice_ctx_init(AVBufferRef *ref) | |||
| { | |||
| AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; | |||
| int ret; | |||
| if (ctx->internal->hw_type->device_init) { | |||
| ret = ctx->internal->hw_type->device_init(ctx); | |||
| if (ret < 0) | |||
| goto fail; | |||
| } | |||
| return 0; | |||
| fail: | |||
| if (ctx->internal->hw_type->device_uninit) | |||
| ctx->internal->hw_type->device_uninit(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) | |||
| { | |||
| AVHWFramesContext *ctx = (AVHWFramesContext*)data; | |||
| if (ctx->internal->pool_internal) | |||
| av_buffer_pool_uninit(&ctx->internal->pool_internal); | |||
| if (ctx->internal->hw_type->frames_uninit) | |||
| ctx->internal->hw_type->frames_uninit(ctx); | |||
| if (ctx->free) | |||
| ctx->free(ctx); | |||
| av_buffer_unref(&ctx->device_ref); | |||
| av_freep(&ctx->hwctx); | |||
| av_freep(&ctx->internal->priv); | |||
| av_freep(&ctx->internal); | |||
| av_freep(&ctx); | |||
| } | |||
| AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in) | |||
| { | |||
| AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref_in->data; | |||
| const HWContextType *hw_type = device_ctx->internal->hw_type; | |||
| AVHWFramesContext *ctx; | |||
| AVBufferRef *buf, *device_ref = NULL;; | |||
| ctx = av_mallocz(sizeof(*ctx)); | |||
| if (!ctx) | |||
| return NULL; | |||
| ctx->internal = av_mallocz(sizeof(*ctx->internal)); | |||
| if (!ctx->internal) | |||
| goto fail; | |||
| if (hw_type->frames_priv_size) { | |||
| ctx->internal->priv = av_mallocz(hw_type->frames_priv_size); | |||
| if (!ctx->internal->priv) | |||
| goto fail; | |||
| } | |||
| 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; | |||
| ctx->format = AV_PIX_FMT_NONE; | |||
| ctx->internal->hw_type = hw_type; | |||
| return buf; | |||
| fail: | |||
| if (device_ref) | |||
| av_buffer_unref(&device_ref); | |||
| if (ctx->internal) | |||
| av_freep(&ctx->internal->priv); | |||
| av_freep(&ctx->internal); | |||
| 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_mallocz_array(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) | |||
| { | |||
| AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data; | |||
| const enum AVPixelFormat *pix_fmt; | |||
| int ret; | |||
| /* validate the pixel format */ | |||
| for (pix_fmt = ctx->internal->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), ctx->internal->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 (ctx->internal->hw_type->frames_init) { | |||
| ret = ctx->internal->hw_type->frames_init(ctx); | |||
| if (ret < 0) | |||
| goto fail; | |||
| } | |||
| if (ctx->internal->pool_internal && !ctx->pool) | |||
| ctx->pool = ctx->internal->pool_internal; | |||
| /* preallocate the frames in the pool, if requested */ | |||
| if (ctx->initial_pool_size > 0) { | |||
| ret = hwframe_pool_prealloc(ref); | |||
| if (ret < 0) | |||
| goto fail; | |||
| } | |||
| return 0; | |||
| fail: | |||
| if (ctx->internal->hw_type->frames_uninit) | |||
| ctx->internal->hw_type->frames_uninit(ctx); | |||
| return ret; | |||
| } | |||
| int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref, | |||
| enum AVHWFrameTransferDirection dir, | |||
| enum AVPixelFormat **formats, int flags) | |||
| { | |||
| AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; | |||
| if (!ctx->internal->hw_type->transfer_get_formats) | |||
| return AVERROR(ENOSYS); | |||
| return ctx->internal->hw_type->transfer_get_formats(ctx, dir, formats); | |||
| } | |||
| static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags) | |||
| { | |||
| AVFrame *frame_tmp; | |||
| int ret = 0; | |||
| 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 = src->width; | |||
| frame_tmp->height = src->height; | |||
| ret = av_frame_get_buffer(frame_tmp, 32); | |||
| if (ret < 0) | |||
| goto fail; | |||
| ret = av_hwframe_transfer_data(frame_tmp, src, flags); | |||
| if (ret < 0) | |||
| goto fail; | |||
| 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) | |||
| { | |||
| AVHWFramesContext *ctx; | |||
| int ret; | |||
| if (!dst->buf[0]) | |||
| return transfer_data_alloc(dst, src, flags); | |||
| if (src->hw_frames_ctx) { | |||
| ctx = (AVHWFramesContext*)src->hw_frames_ctx->data; | |||
| ret = ctx->internal->hw_type->transfer_data_from(ctx, dst, src); | |||
| if (ret < 0) | |||
| return ret; | |||
| } else if (dst->hw_frames_ctx) { | |||
| ctx = (AVHWFramesContext*)dst->hw_frames_ctx->data; | |||
| ret = ctx->internal->hw_type->transfer_data_to(ctx, 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) | |||
| { | |||
| AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; | |||
| int ret; | |||
| if (!ctx->internal->hw_type->frames_get_buffer) | |||
| return AVERROR(ENOSYS); | |||
| if (!ctx->pool) | |||
| return AVERROR(EINVAL); | |||
| frame->hw_frames_ctx = av_buffer_ref(hwframe_ref); | |||
| if (!frame->hw_frames_ctx) | |||
| return AVERROR(ENOMEM); | |||
| ret = ctx->internal->hw_type->frames_get_buffer(ctx, frame); | |||
| if (ret < 0) { | |||
| av_buffer_unref(&frame->hw_frames_ctx); | |||
| return ret; | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -0,0 +1,328 @@ | |||
| /* | |||
| * 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 | |||
| */ | |||
| #ifndef AVUTIL_HWCONTEXT_H | |||
| #define AVUTIL_HWCONTEXT_H | |||
| #include "buffer.h" | |||
| #include "frame.h" | |||
| #include "log.h" | |||
| #include "pixfmt.h" | |||
| enum AVHWDeviceType { | |||
| AV_HWDEVICE_TYPE_VDPAU, | |||
| }; | |||
| typedef struct AVHWDeviceInternal AVHWDeviceInternal; | |||
| /** | |||
| * This struct aggregates all the (hardware/vendor-specific) "high-level" state, | |||
| * i.e. state that is not tied to a concrete processing configuration. | |||
| * E.g., in an API that supports hardware-accelerated encoding and decoding, | |||
| * this struct will (if possible) wrap the state that is common to both encoding | |||
| * and decoding and from which specific instances of encoders or decoders can be | |||
| * derived. | |||
| * | |||
| * This struct is reference-counted with the AVBuffer mechanism. The | |||
| * av_hwdevice_ctx_alloc() constructor yields a reference, whose data field | |||
| * points to the actual AVHWDeviceContext. Further objects derived from | |||
| * AVHWDeviceContext (such as AVHWFramesContext, describing a frame pool with | |||
| * specific properties) will hold an internal reference to it. After all the | |||
| * references are released, the AVHWDeviceContext itself will be freed, | |||
| * optionally invoking a user-specified callback for uninitializing the hardware | |||
| * state. | |||
| */ | |||
| typedef struct AVHWDeviceContext { | |||
| /** | |||
| * A class for logging. Set by av_hwdevice_ctx_alloc(). | |||
| */ | |||
| const AVClass *av_class; | |||
| /** | |||
| * Private data used internally by libavutil. Must not be accessed in any | |||
| * way by the caller. | |||
| */ | |||
| AVHWDeviceInternal *internal; | |||
| /** | |||
| * This field identifies the underlying API used for hardware access. | |||
| * | |||
| * This field is set when this struct is allocated and never changed | |||
| * afterwards. | |||
| */ | |||
| enum AVHWDeviceType type; | |||
| /** | |||
| * The format-specific data, allocated and freed by libavutil along with | |||
| * this context. | |||
| * | |||
| * Should be cast by the user to the format-specific context defined in the | |||
| * corresponding header (hwcontext_*.h) and filled as described in the | |||
| * documentation before calling av_hwdevice_ctx_init(). | |||
| * | |||
| * After calling av_hwdevice_ctx_init() this struct should not be modified | |||
| * by the caller. | |||
| */ | |||
| void *hwctx; | |||
| /** | |||
| * This field may be set by the caller before calling av_hwdevice_ctx_init(). | |||
| * | |||
| * If non-NULL, this callback will be called when the last reference to | |||
| * this context is unreferenced, immediately before it is freed. | |||
| * | |||
| * @note when other objects (e.g an AVHWFramesContext) are derived from this | |||
| * struct, this callback will be invoked after all such child objects | |||
| * are fully uninitialized and their respective destructors invoked. | |||
| */ | |||
| void (*free)(struct AVHWDeviceContext *ctx); | |||
| /** | |||
| * Arbitrary user data, to be used e.g. by the free() callback. | |||
| */ | |||
| void *user_opaque; | |||
| } AVHWDeviceContext; | |||
| typedef struct AVHWFramesInternal AVHWFramesInternal; | |||
| /** | |||
| * This struct describes a set or pool of "hardware" frames (i.e. those with | |||
| * data not located in normal system memory). All the frames in the pool are | |||
| * assumed to be allocated in the same way and interchangeable. | |||
| * | |||
| * This struct is reference-counted with the AVBuffer mechanism and tied to a | |||
| * given AVHWDeviceContext instance. The av_hwframe_ctx_alloc() constructor | |||
| * yields a reference, whose data field points to the actual AVHWFramesContext | |||
| * struct. | |||
| */ | |||
| typedef struct AVHWFramesContext { | |||
| /** | |||
| * A class for logging. | |||
| */ | |||
| const AVClass *av_class; | |||
| /** | |||
| * Private data used internally by libavutil. Must not be accessed in any | |||
| * way by the caller. | |||
| */ | |||
| AVHWFramesInternal *internal; | |||
| /** | |||
| * A reference to the parent AVHWDeviceContext. This reference is owned and | |||
| * managed by the enclosing AVHWFramesContext, but the caller may derive | |||
| * additional references from it. | |||
| */ | |||
| AVBufferRef *device_ref; | |||
| /** | |||
| * The parent AVHWDeviceContext. This is simply a pointer to | |||
| * device_ref->data provided for convenience. | |||
| * | |||
| * Set by libavutil in av_hwframe_ctx_init(). | |||
| */ | |||
| AVHWDeviceContext *device_ctx; | |||
| /** | |||
| * The format-specific data, allocated and freed automatically along with | |||
| * this context. | |||
| * | |||
| * Should be cast by the user to the format-specific context defined in the | |||
| * corresponding header (hwframe_*.h) and filled as described in the | |||
| * documentation before calling av_hwframe_ctx_init(). | |||
| * | |||
| * After any frames using this context are created, the contents of this | |||
| * struct should not be modified by the caller. | |||
| */ | |||
| void *hwctx; | |||
| /** | |||
| * This field may be set by the caller before calling av_hwframe_ctx_init(). | |||
| * | |||
| * If non-NULL, this callback will be called when the last reference to | |||
| * this context is unreferenced, immediately before it is freed. | |||
| */ | |||
| void (*free)(struct AVHWFramesContext *ctx); | |||
| /** | |||
| * Arbitrary user data, to be used e.g. by the free() callback. | |||
| */ | |||
| void *user_opaque; | |||
| /** | |||
| * A pool from which the frames are allocated by av_hwframe_get_buffer(). | |||
| * This field may be set by the caller before calling av_hwframe_ctx_init(). | |||
| * The buffers returned by calling av_buffer_pool_get() on this pool must | |||
| * have the properties described in the documentation in the correponding hw | |||
| * type's header (hwcontext_*.h). The pool will be freed strictly before | |||
| * this struct's free() callback is invoked. | |||
| * | |||
| * This field may be NULL, then libavutil will attempt to allocate a pool | |||
| * internally. Note that certain device types enforce pools allocated at | |||
| * fixed size (frame count), which cannot be extended dynamically. In such a | |||
| * case, initial_pool_size must be set appropriately. | |||
| */ | |||
| AVBufferPool *pool; | |||
| /** | |||
| * Initial size of the frame pool. If a device type does not support | |||
| * dynamically resizing the pool, then this is also the maximum pool size. | |||
| * | |||
| * May be set by the caller before calling av_hwframe_ctx_init(). Must be | |||
| * set if pool is NULL and the device type does not support dynamic pools. | |||
| */ | |||
| int initial_pool_size; | |||
| /** | |||
| * The pixel format identifying the underlying HW surface type. | |||
| * | |||
| * Must be a hwaccel format, i.e. the corresponding descriptor must have the | |||
| * AV_PIX_FMT_FLAG_HWACCEL flag set. | |||
| * | |||
| * Must be set by the user before calling av_hwframe_ctx_init(). | |||
| */ | |||
| enum AVPixelFormat format; | |||
| /** | |||
| * The pixel format identifying the actual data layout of the hardware | |||
| * frames. | |||
| * | |||
| * Must be set by the caller before calling av_hwframe_ctx_init(). | |||
| * | |||
| * @note when the underlying API does not provide the exact data layout, but | |||
| * only the colorspace/bit depth, this field should be set to the fully | |||
| * planar version of that format (e.g. for 8-bit 420 YUV it should be | |||
| * AV_PIX_FMT_YUV420P, not AV_PIX_FMT_NV12 or anything else). | |||
| */ | |||
| enum AVPixelFormat sw_format; | |||
| /** | |||
| * The allocated dimensions of the frames in this pool. | |||
| * | |||
| * Must be set by the user before calling av_hwframe_ctx_init(). | |||
| */ | |||
| int width, height; | |||
| } AVHWFramesContext; | |||
| /** | |||
| * Allocate an AVHWDeviceContext for a given pixel format. | |||
| * | |||
| * @param format a hwaccel pixel format (AV_PIX_FMT_FLAG_HWACCEL must be set | |||
| * on the corresponding format descriptor) | |||
| * @return a reference to the newly created AVHWDeviceContext on success or NULL | |||
| * on failure. | |||
| */ | |||
| AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type); | |||
| /** | |||
| * Finalize the device context before use. This function must be called after | |||
| * the context is filled with all the required information and before it is | |||
| * used in any way. | |||
| * | |||
| * @param ref a reference to the AVHWDeviceContext | |||
| * @return 0 on success, a negative AVERROR code on failure | |||
| */ | |||
| int av_hwdevice_ctx_init(AVBufferRef *ref); | |||
| /** | |||
| * Allocate an AVHWFramesContext tied to a given device context. | |||
| * | |||
| * @param device_ctx a reference to a AVHWDeviceContext. This function will make | |||
| * a new reference for internal use, the one passed to the | |||
| * function remains owned by the caller. | |||
| * @return a reference to the newly created AVHWFramesContext on success or NULL | |||
| * on failure. | |||
| */ | |||
| AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ctx); | |||
| /** | |||
| * Finalize the context before use. This function must be called after the | |||
| * context is filled with all the required information and before it is attached | |||
| * to any frames. | |||
| * | |||
| * @param ref a reference to the AVHWFramesContext | |||
| * @return 0 on success, a negative AVERROR code on failure | |||
| */ | |||
| int av_hwframe_ctx_init(AVBufferRef *ref); | |||
| /** | |||
| * Allocate a new frame attached to the given AVHWFramesContext. | |||
| * | |||
| * @param hwframe_ctx a reference to an AVHWFramesContext | |||
| * @param frame an empty (freshly allocated or unreffed) frame to be filled with | |||
| * newly allocated buffers. | |||
| * @param flags currently unused, should be set to zero | |||
| * @return 0 on success, a negative AVERROR code on failure | |||
| */ | |||
| int av_hwframe_get_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame, int flags); | |||
| /** | |||
| * Copy data to or from a hw surface. At least one of dst/src must have an | |||
| * AVHWFramesContext attached. | |||
| * | |||
| * If src has an AVHWFramesContext attached, then the format of dst (if set) | |||
| * must use one of the formats returned by av_hwframe_transfer_get_formats(src, | |||
| * AV_HWFRAME_TRANSFER_DIRECTION_FROM). | |||
| * If dst has an AVHWFramesContext attached, then the format of src must use one | |||
| * of the formats returned by av_hwframe_transfer_get_formats(dst, | |||
| * AV_HWFRAME_TRANSFER_DIRECTION_TO) | |||
| * | |||
| * dst may be "clean" (i.e. with data/buf pointers unset), in which case the | |||
| * data buffers will be allocated by this function using av_frame_get_buffer(). | |||
| * If dst->format is set, then this format will be used, otherwise (when | |||
| * dst->format is AV_PIX_FMT_NONE) the first acceptable format will be chosen. | |||
| * | |||
| * @param dst the destination frame. dst is not touched on failure. | |||
| * @param src the source frame. | |||
| * @param flags currently unused, should be set to zero | |||
| * @return 0 on success, a negative AVERROR error code on failure. | |||
| */ | |||
| int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags); | |||
| enum AVHWFrameTransferDirection { | |||
| /** | |||
| * Transfer the data from the queried hw frame. | |||
| */ | |||
| AV_HWFRAME_TRANSFER_DIRECTION_FROM, | |||
| /** | |||
| * Transfer the data to the queried hw frame. | |||
| */ | |||
| AV_HWFRAME_TRANSFER_DIRECTION_TO, | |||
| }; | |||
| /** | |||
| * Get a list of possible source or target formats usable in | |||
| * av_hwframe_transfer_data(). | |||
| * | |||
| * @param hwframe_ctx the frame context to obtain the information for | |||
| * @param dir the direction of the transfer | |||
| * @param formats the pointer to the output format list will be written here. | |||
| * The list is terminated with AV_PIX_FMT_NONE and must be freed | |||
| * by the caller when no longer needed using av_free(). | |||
| * If this function returns successfully, the format list will | |||
| * have at least one item (not counting the terminator). | |||
| * On failure, the contents of this pointer are unspecified. | |||
| * @param flags currently unused, should be set to zero | |||
| * @return 0 on success, a negative AVERROR code on failure. | |||
| */ | |||
| int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ctx, | |||
| enum AVHWFrameTransferDirection dir, | |||
| enum AVPixelFormat **formats, int flags); | |||
| #endif /* AVUTIL_HWCONTEXT_H */ | |||
| @@ -0,0 +1,89 @@ | |||
| /* | |||
| * 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 | |||
| */ | |||
| #ifndef AVUTIL_HWCONTEXT_INTERNAL_H | |||
| #define AVUTIL_HWCONTEXT_INTERNAL_H | |||
| #include <stddef.h> | |||
| #include "buffer.h" | |||
| #include "hwcontext.h" | |||
| #include "frame.h" | |||
| #include "pixfmt.h" | |||
| typedef struct HWContextType { | |||
| enum AVHWDeviceType type; | |||
| const char *name; | |||
| /** | |||
| * An array of pixel formats supported by the AVHWFramesContext instances | |||
| * Terminated by AV_PIX_FMT_NONE. | |||
| */ | |||
| const enum AVPixelFormat *pix_fmts; | |||
| /** | |||
| * size of the public hardware-specific context, | |||
| * i.e. AVHWDeviceContext.hwctx | |||
| */ | |||
| size_t device_hwctx_size; | |||
| /** | |||
| * size of the private data, i.e. | |||
| * AVHWDeviceInternal.priv | |||
| */ | |||
| size_t device_priv_size; | |||
| /** | |||
| * size of the public frame pool hardware-specific context, | |||
| * i.e. AVHWFramesContext.hwctx | |||
| */ | |||
| size_t frames_hwctx_size; | |||
| /** | |||
| * size of the private data, i.e. | |||
| * AVHWFramesInternal.priv | |||
| */ | |||
| size_t frames_priv_size; | |||
| int (*device_init)(AVHWDeviceContext *ctx); | |||
| void (*device_uninit)(AVHWDeviceContext *ctx); | |||
| int (*frames_init)(AVHWFramesContext *ctx); | |||
| void (*frames_uninit)(AVHWFramesContext *ctx); | |||
| int (*frames_get_buffer)(AVHWFramesContext *ctx, AVFrame *frame); | |||
| int (*transfer_get_formats)(AVHWFramesContext *ctx, | |||
| enum AVHWFrameTransferDirection dir, | |||
| enum AVPixelFormat **formats); | |||
| int (*transfer_data_to)(AVHWFramesContext *ctx, AVFrame *dst, | |||
| const AVFrame *src); | |||
| int (*transfer_data_from)(AVHWFramesContext *ctx, AVFrame *dst, | |||
| const AVFrame *src); | |||
| } HWContextType; | |||
| struct AVHWDeviceInternal { | |||
| const HWContextType *hw_type; | |||
| void *priv; | |||
| }; | |||
| struct AVHWFramesInternal { | |||
| const HWContextType *hw_type; | |||
| void *priv; | |||
| AVBufferPool *pool_internal; | |||
| }; | |||
| #endif /* AVUTIL_HWCONTEXT_INTERNAL_H */ | |||