In ffmpeg decoding video scenario, H264 for example, typically we allocate an AVFrame
and decode the compressed data, then we get the result fr
I found the way out.
There is a public member of AVCodecContext
, get_buffer2, which is a callback function. While calling avcodec_decode_video2
, this callback function will be invoked, and this callback function is responsible to delegate buffers and some informations to AVFrame
, then avcodec_decode_video2
generate the result to the buffers of AVFrame
.
The callback function, get_buffer2, is set avcodec_default_get_buffer2
as default. However, we can override this as our privided function. For example:
void our_buffer_default_free(void *opaque, uint8_t *data)
{
// empty
}
int our_get_buffer(struct AVCodecContext *c, AVFrame *pic, int flags)
{
assert(c->codec_type == AVMEDIA_TYPE_VIDEO);
pic->data[0] = lrY.pBits;
pic->data[1] = lrU.pBits;
pic->data[2] = lrV.pBits;
picture->linesize[0] = lrY.Pitch;
picture->linesize[1] = lrU.Pitch;
picture->linesize[2] = lrV.Pitch;
pic->buf[0] = av_buffer_create(pic->data[0], pic->linesize[0] * pic->height, our_buffer_default_free, NULL, 0);
pic->buf[1] = av_buffer_create(pic->data[1], pic->linesize[1] * pic->height / 2, our_buffer_default_free, NULL, 0);
pic->buf[2] = av_buffer_create(pic->data[2], pic->linesize[2] * pic->height / 2, our_buffer_default_free, NULL, 0);
return 0;
}
Before decoding, we override the callback function:
context->get_buffer2 = our_get_buffer;
Then avcodec_decode_video2
will generate the result to our provided buffers.
By the way, for C++ programs which often implementing these processes in classes, we can record this pointer first:
context->opaque = this;
And define the overridden callback function as static member:
static int myclass::my_get_buffer(struct AVCodecContext *c, AVFrame *pic, int flags)
{
auto this_pointer = static_cast<decode_context*>(c->opaque);
return this_pointer->my_get_buffer_real(c, pic, flags);
}
int myclass::my_get_buffer_real(struct AVCodecContext *c, AVFrame *pic, int flags)
{
// ditto with above our_get_buffer.
// ...
}