On Mon, 24 Mar 2014 03:01:53 +0100
Luca Barbato <[email protected]> wrote:

> From: Anton Khirnov <[email protected]>
> 
> It leverages the new hwaccel 1.2 features:
> 
> - get_buffer2 is never called
> - the internal context is automatically initialized/deinitialized
> 
> Signed-off-by: Luca Barbato <[email protected]>
> ---
>  libavcodec/Makefile       |   1 +
>  libavcodec/allcodecs.c    |   1 +
>  libavcodec/h264_slice.c   |  23 ++++-
>  libavcodec/vda.c          |  64 ++++++++++++
>  libavcodec/vda.h          |  53 ++++++++++
>  libavcodec/vda_h264.c     | 248 
> ++++++++++++++++++++++++++++++++++++++++++++--
>  libavcodec/vda_internal.h |  33 ++++++
>  7 files changed, 412 insertions(+), 11 deletions(-)
>  create mode 100644 libavcodec/vda.c
>  create mode 100644 libavcodec/vda_internal.h
> 
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 1b5a044..5908011 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -67,6 +67,7 @@ OBJS-$(CONFIG_RDFT)                    += rdft.o 
> $(RDFT-OBJS-yes)
>  OBJS-$(CONFIG_SINEWIN)                 += sinewin.o
>  OBJS-$(CONFIG_TPELDSP)                 += tpeldsp.o
>  OBJS-$(CONFIG_VAAPI)                   += vaapi.o
> +OBJS-$(CONFIG_VDA)                     += vda.o
>  OBJS-$(CONFIG_VDPAU)                   += vdpau.o
>  OBJS-$(CONFIG_VIDEODSP)                += videodsp.o
>  OBJS-$(CONFIG_VP3DSP)                  += vp3dsp.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index ed6d7ff..7b061e6 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -79,6 +79,7 @@ void avcodec_register_all(void)
>      REGISTER_HWACCEL(H264_DXVA2,        h264_dxva2);
>      REGISTER_HWACCEL(H264_VAAPI,        h264_vaapi);
>      REGISTER_HWACCEL(H264_VDA,          h264_vda);
> +    REGISTER_HWACCEL(H264_VDA_OLD,      h264_vda_old);
>      REGISTER_HWACCEL(H264_VDPAU,        h264_vdpau);
>      REGISTER_HWACCEL(MPEG1_VDPAU,       mpeg1_vdpau);
>      REGISTER_HWACCEL(MPEG2_DXVA2,       mpeg2_dxva2);
> diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
> index 73c0740..eb4adde 100644
> --- a/libavcodec/h264_slice.c
> +++ b/libavcodec/h264_slice.c
> @@ -153,6 +153,7 @@ static const enum AVPixelFormat 
> h264_hwaccel_pixfmt_list_420[] = {
>  #endif
>  #if CONFIG_H264_VDA_HWACCEL
>      AV_PIX_FMT_VDA_VLD,
> +    AV_PIX_FMT_VDA,
>  #endif
>  #if CONFIG_H264_VDPAU_HWACCEL
>      AV_PIX_FMT_VDPAU,
> @@ -170,6 +171,7 @@ static const enum AVPixelFormat 
> h264_hwaccel_pixfmt_list_jpeg_420[] = {
>  #endif
>  #if CONFIG_H264_VDA_HWACCEL
>      AV_PIX_FMT_VDA_VLD,
> +    AV_PIX_FMT_VDA,
>  #endif
>  #if CONFIG_H264_VDPAU_HWACCEL
>      AV_PIX_FMT_VDPAU,
> @@ -247,10 +249,23 @@ static int alloc_picture(H264Context *h, H264Picture 
> *pic)
>      av_assert0(!pic->f.data[0]);
>  
>      pic->tf.f = &pic->f;
> -    ret = ff_thread_get_buffer(h->avctx, &pic->tf, pic->reference ?
> -                                                   AV_GET_BUFFER_FLAG_REF : 
> 0);
> -    if (ret < 0)
> -        goto fail;
> +
> +    if (h->avctx->pix_fmt == AV_PIX_FMT_VDA) {
> +        /* the VDA framework handles its surfaces internally, so we
> +         * do not call get_buffer at all;
> +         * create a dummy buffer here until we get the real one later */
> +        pic->f.buf[0] = av_buffer_alloc(1);
> +        pic->f.width  = h->avctx->width;
> +        pic->f.height = h->avctx->height;
> +        pic->f.format = h->avctx->pix_fmt;
> +        if (!pic->f.buf[0])
> +            goto fail;
> +    } else {
> +        ret = ff_thread_get_buffer(h->avctx, &pic->tf, pic->reference ?
> +                                   AV_GET_BUFFER_FLAG_REF : 0);
> +        if (ret < 0)
> +            goto fail;
> +    }

Maybe this could be made a bit nicer by adding a new callback to
AVHWAccel? If that callback is NULL, the code would fall back to 
ff_thread_get_buffer.

>      h->linesize   = pic->f.linesize[0];
>      h->uvlinesize = pic->f.linesize[1];
> diff --git a/libavcodec/vda.c b/libavcodec/vda.c
> new file mode 100644
> index 0000000..60f0b77
> --- /dev/null
> +++ b/libavcodec/vda.c
> @@ -0,0 +1,64 @@
> +/*
> + * 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 "libavutil/mem.h"
> +
> +#include "vda.h"
> +#include "vda_internal.h"
> +
> +#if CONFIG_H264_VDA_HWACCEL
> +AVVDAContext *av_vda_alloc_context(void)
> +{
> +    AVVDAContext *ret = av_mallocz(sizeof(*ret));
> +
> +    if (ret)
> +        ret->output_callback = ff_vda_output_callback;
> +
> +    return ret;
> +}
> +
> +int av_vda_default_init(AVCodecContext *avctx)
> +{
> +    avctx->hwaccel_context = av_vda_alloc_context();
> +    if (!avctx->hwaccel_context)
> +        return AVERROR(ENOMEM);
> +    return ff_vda_default_init(avctx);
> +}
> +
> +void av_vda_default_free(AVCodecContext *avctx)
> +{
> +    ff_vda_default_free(avctx);
> +    av_freep(&avctx->hwaccel_context);
> +}
> +#else
> +AVVDAContext *av_vda_alloc_context(void)
> +{
> +    return NULL;
> +}
> +
> +int av_vda_default_init(AVCodecContext *avctx)
> +{
> +    return AVERROR(ENOSYS);
> +}
> +
> +void av_vda_default_free(AVCodecContext *ctx)
> +{
> +}
> +#endif
> diff --git a/libavcodec/vda.h b/libavcodec/vda.h
> index 1189e41..d9f935d 100644
> --- a/libavcodec/vda.h
> +++ b/libavcodec/vda.h
> @@ -29,6 +29,7 @@
>   * Public libavcodec VDA header.
>   */
>  
> +#include "libavcodec/avcodec.h"
>  #include "libavcodec/version.h"
>  
>  #include <stdint.h>
> @@ -136,6 +137,58 @@ int ff_vda_create_decoder(struct vda_context *vda_ctx,
>  int ff_vda_destroy_decoder(struct vda_context *vda_ctx);
>  
>  /**
> + * This struct holds all the information that needs to be passed
> + * between the caller and libavcodec for initializing VDA decoding.
> + * Its size is not a part of the public ABI, it must be allocated with
> + * av_vda_alloc_context() and freed with av_free().
> + */
> +typedef struct AVVDAContext {
> +    /**
> +     * VDA decoder object. Created and freed by the caller.
> +     */
> +    VDADecoder decoder;
> +
> +    /**
> +     * The output callback that must be passed to VDADecoderCreate.
> +     * Set by av_vda_alloc_context().
> +     */
> +    VDADecoderOutputCallback *output_callback;
> +} AVVDAContext;
> +
> +/**
> + * Allocate and initialize a VDA context.
> + *
> + * This function should be called from the get_format() callback when the 
> caller
> + * selects the AV_PIX_FMT_VDA format. The caller must then create the decoder
> + * object (using the output callback provided by libavcodec) that will be 
> used
> + * for VDA-accelerated decoding.
> + *
> + * When decoding with VDA is finished, the caller must destroy the decoder
> + * object and free the VDA context using av_free().
> + *
> + * @return the newly allocated context or NULL on failure
> + */
> +AVVDAContext *av_vda_alloc_context(void);

I wonder why this is needed at all. Couldn't the hwaccel allocate this
on its own? On the other hand, maybe it's better to keep this function,
to make interaction with get_format easier.

(I'd argue there should be explicit init and uninit callbacks, rather
than just get_format. Currently, it's somewhat hard to tell when you
should allocate the hwaccel context and when you should free it.
Especially with scary use cases in mind like switching hwaccels
mid-stream, which is supposed to work.)

> +/**
> + * This is a convenience function that creates and sets up the VDA context 
> using
> + * an internal implementation.
> + *
> + * @param avctx the corresponding codec context
> + *
> + * @return >= 0 on success, a negative AVERROR code on failure
> + */
> +int av_vda_default_init(AVCodecContext *avctx);
> +
> +/**
> + * This function must be called to free the VDA context initialized with
> + * av_vda_default_init().
> + *
> + * @param avctx the corresponding codec context
> + */
> +void av_vda_default_free(AVCodecContext *avctx);
> +
> +/**
>   * @}
>   */
>  
> diff --git a/libavcodec/vda_h264.c b/libavcodec/vda_h264.c
> index 72b0c78..3cae992 100644
> --- a/libavcodec/vda_h264.c
> +++ b/libavcodec/vda_h264.c
> @@ -26,7 +26,9 @@
>  
>  #include "libavutil/avutil.h"
>  #include "h264.h"
> +#include "internal.h"
>  #include "vda.h"
> +#include "vda_internal.h"
>  
>  typedef struct VDAContext {
>      // The current bitstream buffer.
> @@ -37,6 +39,8 @@ typedef struct VDAContext {
>  
>      // The reference size used for fast reallocation.
>      int                  allocated_size;
> +
> +    CVImageBufferRef frame;
>  } VDAContext;
>  
>  /* Decoder callback that adds the VDA frame to the queue in display order. */
> @@ -78,7 +82,7 @@ static int vda_sync_decode(VDAContext *ctx, struct 
> vda_context *vda_ctx)
>  }
>  
>  
> -static int vda_h264_start_frame(AVCodecContext *avctx,
> +static int vda_old_h264_start_frame(AVCodecContext *avctx,
>                                  av_unused const uint8_t *buffer,
>                                  av_unused uint32_t size)
>  {
> @@ -93,7 +97,7 @@ static int vda_h264_start_frame(AVCodecContext *avctx,
>      return 0;
>  }
>  
> -static int vda_h264_decode_slice(AVCodecContext *avctx,
> +static int vda_old_h264_decode_slice(AVCodecContext *avctx,
>                                   const uint8_t *buffer,
>                                   uint32_t size)
>  {
> @@ -120,7 +124,7 @@ static int vda_h264_decode_slice(AVCodecContext *avctx,
>      return 0;
>  }
>  
> -static int vda_h264_end_frame(AVCodecContext *avctx)
> +static int vda_old_h264_end_frame(AVCodecContext *avctx)
>  {
>      H264Context *h                      = avctx->priv_data;
>      VDAContext *vda                     = avctx->internal->hwaccel_priv_data;
> @@ -208,7 +212,7 @@ int ff_vda_create_decoder(struct vda_context *vda_ctx,
>  
>      status = VDADecoderCreate(config_info,
>                                buffer_attributes,
> -                              vda_decoder_callback,
> +                              (VDADecoderOutputCallback 
> *)vda_decoder_callback,
>                                vda_ctx,
>                                &vda_ctx->decoder);
>  
> @@ -234,17 +238,247 @@ int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
>      return status;
>  }
>  
> -static void vda_h264_uninit(AVCodecContext *avctx)
> +static int vda_h264_uninit(AVCodecContext *avctx)
>  {
> -    VDAContext *vda = avctx->internal->priv_data;
> +    VDAContext *vda = avctx->internal->hwaccel_priv_data;
>      av_freep(&vda->bitstream);
> +    if (vda->frame)
> +        CVPixelBufferRelease(vda->frame);
> +    return 0;
>  }
>  
> -AVHWAccel ff_h264_vda_hwaccel = {
> +AVHWAccel ff_h264_vda_old_hwaccel = {
>      .name           = "h264_vda",
>      .type           = AVMEDIA_TYPE_VIDEO,
>      .id             = AV_CODEC_ID_H264,
>      .pix_fmt        = AV_PIX_FMT_VDA_VLD,
> +    .start_frame    = vda_old_h264_start_frame,
> +    .decode_slice   = vda_old_h264_decode_slice,
> +    .end_frame      = vda_old_h264_end_frame,
> +    .uninit         = vda_h264_uninit,
> +    .priv_data_size = sizeof(VDAContext),
> +};
> +
> +void ff_vda_output_callback(void *opaque,
> +                            CFDictionaryRef user_info,
> +                            OSStatus status,
> +                            uint32_t infoFlags,
> +                            CVImageBufferRef image_buffer)
> +{
> +    AVCodecContext *ctx = opaque;
> +    VDAContext *vda = ctx->internal->hwaccel_priv_data;
> +
> +
> +    if (vda->frame) {
> +        CVPixelBufferRelease(vda->frame);
> +        vda->frame = NULL;
> +    }
> +
> +    if (!image_buffer)
> +        return;
> +
> +    vda->frame = CVPixelBufferRetain(image_buffer);
> +}
> +
> +static int vda_h264_start_frame(AVCodecContext *avctx,
> +                                const uint8_t *buffer,
> +                                uint32_t size)
> +{
> +    VDAContext *vda = avctx->internal->hwaccel_priv_data;
> +
> +    vda->bitstream_size = 0;
> +
> +    return 0;
> +}
> +
> +static int vda_h264_decode_slice(AVCodecContext *avctx,
> +                                 const uint8_t *buffer,
> +                                 uint32_t size)
> +{
> +    VDAContext *vda       = avctx->internal->hwaccel_priv_data;
> +    void *tmp;
> +
> +    tmp = av_fast_realloc(vda->bitstream,
> +                          &vda->allocated_size,
> +                          vda->bitstream_size + size + 4);
> +    if (!tmp)
> +        return AVERROR(ENOMEM);
> +
> +    vda->bitstream = tmp;
> +
> +    AV_WB32(vda->bitstream + vda->bitstream_size, size);
> +    memcpy(vda->bitstream + vda->bitstream_size + 4, buffer, size);
> +
> +    vda->bitstream_size += size + 4;
> +
> +    return 0;
> +}
> +
> +static void release_buffer(void *opaque, uint8_t *data)
> +{
> +    CVImageBufferRef frame = (CVImageBufferRef)data;
> +    CVPixelBufferRelease(frame);
> +}
> +
> +static int vda_h264_end_frame(AVCodecContext *avctx)
> +{
> +    H264Context *h        = avctx->priv_data;
> +    VDAContext *vda       = avctx->internal->hwaccel_priv_data;
> +    AVVDAContext *vda_ctx = avctx->hwaccel_context;
> +    AVFrame *frame        = &h->cur_pic_ptr->f;
> +    uint32_t flush_flags  = 1 << 0; ///< kVDADecoderFlush_emitFrames
> +    CFDataRef coded_frame;
> +    OSStatus status;
> +
> +    if (!vda->bitstream_size)
> +        return AVERROR_INVALIDDATA;
> +
> +
> +    coded_frame = CFDataCreate(kCFAllocatorDefault,
> +                               vda->bitstream,
> +                               vda->bitstream_size);
> +
> +    status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL);
> +
> +    if (status == kVDADecoderNoErr)
> +        status = VDADecoderFlush(vda_ctx->decoder, flush_flags);
> +
> +    CFRelease(coded_frame);
> +
> +    if (status != kVDADecoderNoErr) {
> +        av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
> +        return AVERROR_UNKNOWN;
> +    }
> +
> +    if (vda->frame) {
> +        av_buffer_unref(&frame->buf[0]);
> +
> +        frame->buf[0] = av_buffer_create((uint8_t*)vda->frame,
> +                                         sizeof(vda->frame),
> +                                         release_buffer, NULL,
> +                                         AV_BUFFER_FLAG_READONLY);
> +        if (!frame->buf)
> +            return AVERROR(ENOMEM);
> +
> +        frame->data[3] = (uint8_t*)vda->frame;
> +        vda->frame = NULL;
> +    }
> +
> +    return 0;
> +}
> +
> +int ff_vda_default_init(AVCodecContext *avctx)

Maybe I'm missing something here, but shouldn't this be
av_vda_default_init?

> +{
> +    AVVDAContext *vda_ctx = avctx->hwaccel_context;
> +    OSStatus status = kVDADecoderNoErr;
> +    CFNumberRef height;
> +    CFNumberRef width;
> +    CFNumberRef format;
> +    CFDataRef avc_data;
> +    CFMutableDictionaryRef config_info;
> +    CFMutableDictionaryRef buffer_attributes;
> +    CFMutableDictionaryRef io_surface_properties;
> +    CFNumberRef cv_pix_fmt;
> +    int32_t fmt = 'avc1', pix_fmt = kCVPixelFormatType_422YpCbCr8;
> +
> +    // kCVPixelFormatType_420YpCbCr8Planar;
> +
> +    /* Each VCL NAL in the bistream sent to the decoder
> +     * is preceded by a 4 bytes length header.
> +     * Change the avcC atom header if needed, to signal headers of 4 bytes. 
> */
> +    if (avctx->extradata_size >= 4 && (avctx->extradata[4] & 0x03) != 0x03) {
> +        uint8_t *rw_extradata;
> +
> +        if (!(rw_extradata = av_malloc(avctx->extradata_size)))
> +            return AVERROR(ENOMEM);
> +
> +        memcpy(rw_extradata, avctx->extradata, avctx->extradata_size);
> +
> +        rw_extradata[4] |= 0x03;
> +
> +        avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, 
> avctx->extradata_size);
> +
> +        av_freep(&rw_extradata);
> +    } else {
> +        avc_data = CFDataCreate(kCFAllocatorDefault,
> +                                avctx->extradata, avctx->extradata_size);
> +    }
> +
> +    config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
> +                                            4,
> +                                            &kCFTypeDictionaryKeyCallBacks,
> +                                            
> &kCFTypeDictionaryValueCallBacks);
> +
> +    height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, 
> &avctx->height);
> +    width  = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, 
> &avctx->width);
> +    format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &fmt);
> +    CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, 
> height);
> +    CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width);
> +    CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, 
> avc_data);
> +    CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, 
> format);
> +
> +    buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
> +                                                  2,
> +                                                  
> &kCFTypeDictionaryKeyCallBacks,
> +                                                  
> &kCFTypeDictionaryValueCallBacks);
> +    io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
> +                                                      0,
> +                                                      
> &kCFTypeDictionaryKeyCallBacks,
> +                                                      
> &kCFTypeDictionaryValueCallBacks);
> +    cv_pix_fmt      = CFNumberCreate(kCFAllocatorDefault,
> +                                     kCFNumberSInt32Type,
> +                                     &pix_fmt);
> +
> +    CFDictionarySetValue(buffer_attributes,
> +                         kCVPixelBufferPixelFormatTypeKey,
> +                         cv_pix_fmt);
> +    CFDictionarySetValue(buffer_attributes,
> +                         kCVPixelBufferIOSurfacePropertiesKey,
> +                         io_surface_properties);
> +
> +    status = VDADecoderCreate(config_info,
> +                              buffer_attributes,
> +                              (VDADecoderOutputCallback 
> *)ff_vda_output_callback,
> +                              avctx,
> +                              &vda_ctx->decoder);
> +
> +    CFRelease(format);
> +    CFRelease(height);
> +    CFRelease(width);
> +    CFRelease(avc_data);
> +    CFRelease(config_info);
> +
> +    if (status != kVDADecoderNoErr) {
> +        av_log(avctx, AV_LOG_ERROR, "Cannot initialize VDA %d\n", status);
> +    }
> +
> +    switch (status) {
> +    case kVDADecoderHardwareNotSupportedErr:
> +    case kVDADecoderFormatNotSupportedErr:
> +        return AVERROR(ENOSYS);
> +    case kVDADecoderConfigurationError:
> +        return AVERROR(EINVAL);
> +    case kVDADecoderDecoderFailedErr:
> +        return AVERROR_INVALIDDATA;

I'm really quite suspicious about this error code mapping. API users
need the guarantee that this mapping if fixed and that there's e.g. no
other reason AVERROR_INVALIDDATA could be returned. Or even better:
return the native VDA error code in some way. Either directly, or using
an additional parameter?

> +    case kVDADecoderNoErr:
> +        return 0;
> +    default:
> +        return AVERROR_UNKNOWN;
> +    }
> +}
> +
> +void ff_vda_default_free(AVCodecContext *avctx)
> +{
> +    AVVDAContext *vda = avctx->hwaccel_context;
> +    if (vda && vda->decoder)
> +        VDADecoderDestroy(vda->decoder);
> +}
> +
> +AVHWAccel ff_h264_vda_hwaccel = {
> +    .name           = "h264_vda",
> +    .type           = AVMEDIA_TYPE_VIDEO,
> +    .id             = AV_CODEC_ID_H264,
> +    .pix_fmt        = AV_PIX_FMT_VDA,
>      .start_frame    = vda_h264_start_frame,
>      .decode_slice   = vda_h264_decode_slice,
>      .end_frame      = vda_h264_end_frame,
> diff --git a/libavcodec/vda_internal.h b/libavcodec/vda_internal.h
> new file mode 100644
> index 0000000..9d0ed80
> --- /dev/null
> +++ b/libavcodec/vda_internal.h
> @@ -0,0 +1,33 @@
> +/*
> + * 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 AVCODEC_VDA_INTERNAL_H
> +#define AVCODEC_VDA_INTERNAL_H
> +
> +#include "vda.h"
> +
> +void ff_vda_output_callback(void *vda_hw_ctx,
> +                            CFDictionaryRef user_info,
> +                            OSStatus status,
> +                            uint32_t infoFlags,
> +                            CVImageBufferRef image_buffer);
> +
> +int ff_vda_default_init(AVCodecContext *avctx);
> +void ff_vda_default_free(AVCodecContext *avctx);
> +
> +#endif /* AVCODEC_VDA_INTERNAL_H */

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to