On Tue,  2 Feb 2016 12:41:22 +0100
Anton Khirnov <[email protected]> wrote:

> ---
>  libavutil/Makefile             |   2 +
>  libavutil/frame.c              |  11 ++
>  libavutil/frame.h              |   2 +
>  libavutil/hwcontext.c          | 401 
> +++++++++++++++++++++++++++++++++++++++++
>  libavutil/hwcontext.h          | 325 +++++++++++++++++++++++++++++++++
>  libavutil/hwcontext_internal.h |  89 +++++++++
>  6 files changed, 830 insertions(+)
>  create mode 100644 libavutil/hwcontext.c
>  create mode 100644 libavutil/hwcontext.h
>  create mode 100644 libavutil/hwcontext_internal.h
> 
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index 17bd57e..2c0b7b5 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -23,6 +23,7 @@ HEADERS = adler32.h                                         
>             \
>            file.h                                                        \
>            frame.h                                                       \
>            hmac.h                                                        \
> +          hwcontext.h                                                   \
>            imgutils.h                                                    \
>            intfloat.h                                                    \
>            intreadwrite.h                                                \
> @@ -78,6 +79,7 @@ OBJS = adler32.o                                            
>             \
>         float_dsp.o                                                      \
>         frame.o                                                          \
>         hmac.o                                                           \
> +       hwcontext.o                                                      \
>         imgutils.o                                                       \
>         intmath.o                                                        \
>         lfg.o                                                            \
> diff --git a/libavutil/frame.c b/libavutil/frame.c
> index 15276fe..fd954c6 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/hwcontext.c b/libavutil/hwcontext.c
> new file mode 100644
> index 0000000..81093f9
> --- /dev/null
> +++ b/libavutil/hwcontext.c
> @@ -0,0 +1,401 @@
> +/*
> + * 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 "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]);
> +        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(const AVFrame *frame,
> +                                    enum AVHWFrameTransferDirection dir,
> +                                    enum AVPixelFormat **formats)
> +{
> +    AVHWFramesContext *ctx;
> +
> +    if (!frame->hw_ctx)
> +        return AVERROR(EINVAL);
> +
> +    ctx = (AVHWFramesContext*)frame->hw_ctx->data;
> +
> +    if (!ctx->internal->hw_type->transfer_get_formats)
> +        return AVERROR(ENOSYS);
> +
> +    return ctx->internal->hw_type->transfer_get_formats(ctx, frame, dir, 
> formats);
> +}
> +
> +static int transfer_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_transfer_get_formats(src, 
> AV_HWFRAME_TRANSFER_DIRECTION_FROM,
> +                                              &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;
> +
> +    ret = av_hwframe_transfer_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_transfer_data(AVFrame *dst, const AVFrame *src)
> +{
> +    AVHWFramesContext *ctx;
> +    int ret;
> +
> +    if (!dst->buf[0])
> +        return transfer_data_alloc(dst, src);
> +
> +    if (src->hw_ctx) {
> +        ctx = (AVHWFramesContext*)src->hw_ctx->data;
> +
> +        ret = ctx->internal->hw_type->transfer_data_from(ctx, dst, src);
> +        if (ret < 0)
> +            return ret;
> +    } else if (dst->hw_ctx) {
> +        ctx = (AVHWFramesContext*)dst->hw_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)
> +{
> +    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_ctx = av_buffer_ref(hwframe_ref);
> +    if (!frame->hw_ctx)
> +        return AVERROR(ENOMEM);
> +
> +    ret = ctx->internal->hw_type->frames_get_buffer(ctx, frame);
> +    if (ret < 0) {
> +        av_buffer_unref(&frame->hw_ctx);
> +        return ret;
> +    }
> +
> +    return 0;
> +}
> diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h
> new file mode 100644
> index 0000000..ee556cd
> --- /dev/null
> +++ b/libavutil/hwcontext.h
> @@ -0,0 +1,325 @@
> +/*
> + * 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_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.
> + * @return 0 on success, a negative AVERROR code on failure
> + */
> +int av_hwframe_get_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame);
> +
> +/**
> + * 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.
> + * @return 0 on success, a negative AVERROR error code on failure.
> + */
> +int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src);
> +
> +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 frame the frame 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.
> + * @return 0 on success, a negative AVERROR code on failure.
> + */
> +int av_hwframe_transfer_get_formats(const AVFrame *frame,
> +                                    enum AVHWFrameTransferDirection dir,
> +                                    enum AVPixelFormat **formats);
> +
> +
> +#endif /* AVUTIL_HWCONTEXT_H */
> diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h
> new file mode 100644
> index 0000000..090b60d
> --- /dev/null
> +++ b/libavutil/hwcontext_internal.h
> @@ -0,0 +1,89 @@
> +/*
> + * 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_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, const 
> AVFrame *frame,
> +                                             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 */

I still think AVFrame should have an accessor for the hwcontext,
instead of forcing the user to mess with bufferrefs and void pointers.
I think this bufferref stuff is much more awkward than a dumb
av_hwcontext_ref/unref() function ever could be.

In general this probably goes into the right direction, but I'm still
unsure about the details.

(My feeling is just bit like that the abstraction layer adds a bit too
much noise over the actual API.)

Other than that I have no actual complaints, though.
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to