On Sun, 20 Dec 2015 20:59:27 +0100
Anton Khirnov <[email protected]> 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
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel