On Sun, 20 Dec 2015 20:59:27 +0100 Anton Khirnov <an...@khirnov.net> wrote:
> --- > libavutil/Makefile | 2 + > libavutil/frame.c | 11 +++ > libavutil/frame.h | 2 + > libavutil/hwframe.c | 202 > +++++++++++++++++++++++++++++++++++++++++++ > libavutil/hwframe.h | 97 +++++++++++++++++++++ > libavutil/hwframe_internal.h | 54 ++++++++++++ > 6 files changed, 368 insertions(+) > create mode 100644 libavutil/hwframe.c > create mode 100644 libavutil/hwframe.h > create mode 100644 libavutil/hwframe_internal.h > > diff --git a/libavutil/Makefile b/libavutil/Makefile > index 17bd57e..9dd6a78 100644 > --- a/libavutil/Makefile > +++ b/libavutil/Makefile > @@ -23,6 +23,7 @@ HEADERS = adler32.h > \ > file.h \ > frame.h \ > hmac.h \ > + hwframe.h \ > imgutils.h \ > intfloat.h \ > intreadwrite.h \ > @@ -78,6 +79,7 @@ OBJS = adler32.o > \ > float_dsp.o \ > frame.o \ > hmac.o \ > + hwframe.o \ > imgutils.o \ > intmath.o \ > lfg.o \ > diff --git a/libavutil/frame.c b/libavutil/frame.c > index e4f6ab3..6e21942 100644 > --- a/libavutil/frame.c > +++ b/libavutil/frame.c > @@ -251,6 +251,14 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src) > } > } > > + if (src->hw_ctx) { > + dst->hw_ctx = av_buffer_ref(src->hw_ctx); > + if (!dst->hw_ctx) { > + ret = AVERROR(ENOMEM); > + goto fail; > + } > + } > + > /* duplicate extended data */ > if (src->extended_data != src->data) { > int ch = av_get_channel_layout_nb_channels(src->channel_layout); > @@ -303,6 +311,9 @@ void av_frame_unref(AVFrame *frame) > for (i = 0; i < frame->nb_extended_buf; i++) > av_buffer_unref(&frame->extended_buf[i]); > av_freep(&frame->extended_buf); > + > + av_buffer_unref(&frame->hw_ctx); > + > get_frame_defaults(frame); > } > > diff --git a/libavutil/frame.h b/libavutil/frame.h > index c723cb0..14dcabe 100644 > --- a/libavutil/frame.h > +++ b/libavutil/frame.h > @@ -354,6 +354,8 @@ typedef struct AVFrame { > enum AVColorSpace colorspace; > > enum AVChromaLocation chroma_location; > + > + AVBufferRef *hw_ctx; > } AVFrame; > > /** > diff --git a/libavutil/hwframe.c b/libavutil/hwframe.c > new file mode 100644 > index 0000000..15fb32c > --- /dev/null > +++ b/libavutil/hwframe.c > @@ -0,0 +1,202 @@ > +/* > + * This file is part of Libav. > + * > + * Libav 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. > + * > + * Libav 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 Libav; 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 "hwframe.h" > +#include "hwframe_internal.h" > +#include "log.h" > +#include "mem.h" > + > +static const HWFrameType *hw_table[] = { > +}; > + > +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; > + > + /* 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->uninit) > + ctx->internal->hw_type->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_hwframe_ctx_alloc(enum AVPixelFormat format) > +{ > + AVHWFramesContext *ctx; > + AVBufferRef *buf; > + const HWFrameType *hw_type = NULL; > + int i; > + > + for (i = 0; i < FF_ARRAY_ELEMS(hw_table); i++) { > + if (hw_table[i]->format == format) { > + 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->priv_size) { > + ctx->internal->priv = av_mallocz(hw_type->priv_size); > + if (!ctx->internal->priv) > + goto fail; > + } > + > + if (hw_type->hwctx_size) { > + ctx->hwctx = av_mallocz(hw_type->hwctx_size); > + if (!ctx->hwctx) > + goto fail; > + } > + > + buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), > + hwframe_ctx_free, NULL, > + AV_BUFFER_FLAG_READONLY); > + if (!buf) > + goto fail; > + > + ctx->format = format; > + ctx->av_class = &hwframe_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_hwframe_ctx_init(AVBufferRef *ref) > +{ > + AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data; > + int ret; > + > + if (ctx->internal->hw_type->init) { > + ret = ctx->internal->hw_type->init(ctx); > + if (ret < 0) > + goto fail; > + } > + > + return 0; > +fail: > + if (ctx->internal->hw_type->uninit) > + ctx->internal->hw_type->uninit(ctx); > + return ret; > +} > + > +int av_hwframe_get_target_formats(const AVFrame *frame, enum AVPixelFormat > **formats) > +{ > + AVHWFramesContext *ctx; > + > + if (!frame->hw_ctx) > + return AVERROR(EINVAL); > + > + ctx = (AVHWFramesContext*)frame->hw_ctx->data; > + > + if (!ctx->internal->hw_type->get_target_formats) > + return AVERROR(ENOSYS); > + > + return ctx->internal->hw_type->get_target_formats(ctx, frame, formats); > +} > + > +static int retrieve_data_alloc(AVFrame *dst, const AVFrame *src) > +{ > + 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_get_target_formats(src, &formats); > + 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; Would be nice if this function could get its frames from a memory pool. (Or maybe a function like av_hwframe_retrieve_data(), which creates/recreates a pool as needed?) > + > + ret = av_hwframe_retrieve_data(frame_tmp, src); > + if (ret < 0) > + goto fail; > + > + av_frame_move_ref(dst, frame_tmp); > + > +fail: > + av_frame_free(&frame_tmp); > + return ret; > +} > + > +int av_hwframe_retrieve_data(AVFrame *dst, const AVFrame *src) > +{ > + AVHWFramesContext *ctx; > + > + if (!dst->buf[0]) > + return retrieve_data_alloc(dst, src); > + > + if (!src->hw_ctx) > + return AVERROR(EINVAL); > + > + ctx = (AVHWFramesContext*)src->hw_ctx->data; > + > + if (!ctx->internal->hw_type->retrieve_data) > + return AVERROR(ENOSYS); > + > + return ctx->internal->hw_type->retrieve_data(ctx, dst, src); > +} > diff --git a/libavutil/hwframe.h b/libavutil/hwframe.h > new file mode 100644 > index 0000000..3e33aa5 > --- /dev/null > +++ b/libavutil/hwframe.h > @@ -0,0 +1,97 @@ > +/* > + * This file is part of Libav. > + * > + * Libav 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. > + * > + * Libav 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 Libav; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#ifndef AVUTIL_HWFRAME_H > +#define AVUTIL_HWFRAME_H > + > +#include "buffer.h" > +#include "frame.h" > +#include "log.h" > +#include "pixfmt.h" > + > +typedef struct AVHWFramesInternal AVHWFramesInternal; > + > +/** > + * This struct aggregates any state necessary for handling "hardware" frames > + * (i.e. those with data not located in normal system memory). > + * > + * This struct is reference-counted with the AVBuffer mechanism. 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; > + > + /** > + * 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. > + * > + * This field is set when this struct is allocated and never changed > + * afterwards. > + */ > + enum AVPixelFormat format; > + > + /** > + * 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 creating any frames using this context. > + * > + * After any frames using this context are created, the contents of this > + * struct should not be modified by the caller. > + */ > + void *hwctx; > + > + /** > + * Private data used internally by libavutil. Must not be accessed in any > + * way by the caller. > + */ > + AVHWFramesInternal *internal; > + > + /** > + * This field may be set by the caller immediately after allocating this > + * context. > + * > + * If non-NULL, this callback will be called when the last reference to > + * this context is unreferences, 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; > +} AVHWFramesContext; > + > +AVBufferRef *av_hwframe_ctx_alloc(enum AVPixelFormat format); > + > +int av_hwframe_ctx_init(AVBufferRef *ref); > + > +int av_hwframe_get_target_formats(const AVFrame *frame, > + enum AVPixelFormat **formats); > + > +int av_hwframe_retrieve_data(AVFrame *dst, const AVFrame *src); > + > +#endif /* AVUTIL_HWFRAME_H */ > diff --git a/libavutil/hwframe_internal.h b/libavutil/hwframe_internal.h > new file mode 100644 > index 0000000..cae6ef9 > --- /dev/null > +++ b/libavutil/hwframe_internal.h > @@ -0,0 +1,54 @@ > +/* > + * This file is part of Libav. > + * > + * Libav 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. > + * > + * Libav 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 Libav; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#ifndef AVUTIL_HWFRAME_INTERNAL_H > +#define AVUTIL_HWFRAME_INTERNAL_H > + > +#include <stddef.h> > + > +#include "hwframe.h" > +#include "frame.h" > +#include "pixfmt.h" > + > +typedef struct HWFrameType { > + enum AVPixelFormat format; > + const char *name; > + /** > + * size of the public hardware-specific context, > + * i.e. AVHWFramesContext.hwctx > + */ > + size_t hwctx_size; > + /** > + * size of the private data, i.e. > + * AVHWFramesInternal.priv > + */ > + size_t priv_size; > + int (*init)(AVHWFramesContext *ctx); > + void (*uninit)(AVHWFramesContext *ctx); > + int (*get_target_formats)(AVHWFramesContext *ctx, const > AVFrame *frame, > + enum AVPixelFormat **formats); > + int (*retrieve_data)(AVHWFramesContext *ctx, AVFrame *dst, > + const AVFrame *src); > +} HWFrameType; > + > +struct AVHWFramesInternal { > + const HWFrameType *hw_type; > + void *priv; > +}; > + > +#endif /* AVUTIL_HWFRAME_INTERNAL_H */ _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel