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)