FFmpeg vda usage
Sebastien Zwickert edited this page Jun 8, 2013
·
9 revisions
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)
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)