Skip to content

FFmpeg vda usage

Sebastien Zwickert edited this page Jun 8, 2013 · 9 revisions

Reference counted buffer API

Get buffer API (deprecated)

Reference counted buffer API

Define a core video pixel buffer context and its custom freeing callback:

typedef struct {
    CVPixelBufferRef cv_buffer;
} vda_buffer_context;

static void release_vda_context(void *opaque, uint8_t *data)
{
    vda_buffer_context *vda_context = opaque;
    av_free(vda_context);
}

Setup av codec context callbacks:

AVCodecContext *ctx;
/* Init context... */
ctx->get_format = myGetFormatCallback;
ctx->get_buffer2 = myGetBufferCallback;

/* Find and open, etc... */

In get_format callback, try to init vda if ctx pixel format is PIX_FMT_VDA_VLD:

struct vda_context vda_ctx;
vda_ctx = calloc(1,sizeof(vda_context));
vda_ctx.decoder = NULL;
vda_ctx.width = ctx->width;
vda_ctx.height = ctx->height;
vda_ctx.format = 'avc1';
vda_ctx.cv_pix_fmt_type = kCVPixelFormatType_422YpCbCr8;
vda_ctx.use_ref_buffer = 1;

int status = ff_vda_create_decoder(vda_ctx,ctx->extradata,ctx->extradata_size);

if (status)
    // failed to create decoder.
    // free allocated data and give the hand...
else
    ctx->hwaccel_context = vda_ctx;

Then in get_buffer2 callback:

// setup av buffer
vda_buffer_context *vda_context = av_mallocz(sizeof(*vda_context));
AVBufferRef *buffer = av_buffer_create(NULL, 0, release_vda_context, vda_context, 0);

if( !vda_context || !buffer )
{
    av_free(vda_context);
    return -1;
}

av_frame->buf[0] = buffer;
av_frame->data[0] = (void *)1;
return 0;

Extract decoded frame from vda context:

// AVFrame's data[3] contains the CVPixelBufferRef object.
CVPixelBufferRef cv_buffer = ( CVPixelBufferRef )avframe->data[3];

If you need to manage the lifetime of the vda core video pixel buffer you can attach it to your av buffer context when getting the decoded frame from vda:

AVBufferRef *buffer = av_frame->buf[0];
vda_buffer_context *context = av_buffer_get_opaque(buffer);
// AVFrame's data[3] contains the CVPixelBufferRef object.
CVPixelBufferRef cv_buffer = ( CVPixelBufferRef )av_frame->data[3];
context->cv_buffer = CVPixelBufferRetain(cv_buffer);
/*
 * Do not forget to release the retained cv buffer in your custom av buffer freeing callback.
 * in release_vda_context():
 * CVPixelBufferRelease(vda_context->cv_buffer);
 */

On closing destroy vda:

ff_vda_destroy_decoder
free(vda_ctx)

Get buffer API (deprecated)

AVCodecContext *ctx;
/* Init context... */
ctx->get_format = myGetFormatCallback;
ctx->get_buffer = myGetBufferCallback;
ctx->release_buffer = myReleaseBufferCallback;

/* Find and open, etc... */

In get_format callback, try to init vda if ctx pixel format is PIX_FMT_VDA_VLD:

struct vda_context vda_ctx;
vda_ctx = calloc(1,sizeof(vda_context));
vda_ctx.decoder = NULL;
vda_ctx.width = ctx->width;
vda_ctx.height = ctx->height;
vda_ctx.format = 'avc1';
vda_ctx.cv_pix_fmt_type = kCVPixelFormatType_422YpCbCr8;
vda_ctx.use_sync_decoding = 1; // recommended, async decoding is deprecated.

int status = ff_vda_create_decoder(vda_ctx,ctx->extradata,ctx->extradata_size);

if (status)
    // failed to create decoder.
    // free allocated data and give the hand...
else
    ctx->hwaccel_context = vda_ctx;

Then in get_buffer callback:

set type of the frame to FF_BUFFER_TYPE_USER.
init frame data[0] and [3] to fake value (1 for example).

Extract decoded frame from vda context:

// AVFrame's data[3] contains the CVPixelBufferRef object.
CVPixelBufferRef cv_buffer = ( CVPixelBufferRef )avframe->data[3];

In release_buffer callback:

// You are responsible to free the core video buffer

CVPixelBufferRef cv_buffer = ( CVPixelBufferRef )p_ff->data[3];

if ( cv_buffer )
    CFRelease( cv_buffer );

On closing destroy vda:

ff_vda_destroy_decoder
free(vda_ctx)
Clone this wiki locally