[libav-devel] [PATCH 1/5] lavu: add a framework for handling hwaccel frames

wm4 nfxjfg at googlemail.com
Sun Dec 27 14:29:11 CET 2015


On Sun, 20 Dec 2015 20:59:27 +0100
Anton Khirnov <anton at 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 */



More information about the libav-devel mailing list