在ffmpeg解码视频场景中,例如 H264 ,通常我们会分配一个AVFrame
并解码压缩数据,然后我们从成员data
获得结果{ {1}}的{1}}。如下代码:
linesize
我们可以使用结果执行其他任务,例如,使用DirectX9进行渲染。也就是说,准备缓冲区(DirectX9纹理),并从解码结果中复制。
AVFrame
此过程被视为 2副本(ffmpeg将结果复制到picture->数据,然后将图片>数据复制到DirectX9纹理)。
我的问题是:是否可以将流程改进为仅 1份?另一方面,我们可以向ffmpeg提供缓冲区(// input setting: data and size are a H264 data.
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = const_cast<uint8_t*>(data);
avpkt.size = size;
// decode video: H264 ---> YUV420
AVFrame *picture = avcodec_alloc_frame();
int len = avcodec_decode_video2(context, picture, &got_picture, &avpkt);
,DirectX9纹理的缓冲区),并将函数结果解码为DirectX9纹理的缓冲区,而不是D3DLOCKED_RECT lrY;
D3DLOCKED_RECT lrU;
D3DLOCKED_RECT lrV;
textureY->LockRect(0, &lrY, NULL, 0);
textureU->LockRect(0, &lrU, NULL, 0);
textureV->LockRect(0, &lrV, NULL, 0);
// copy YUV420: picture->data ---> lr.pBits.
my_copy_image_function(picture->data[0], picture->linesize[0], lrY.pBits, lrY.Pitch, width, height);
my_copy_image_function(picture->data[1], picture->linesize[1], lrU.pBits, lrU.Pitch, width / 2, height / 2);
my_copy_image_function(picture->data[2], picture->linesize[2], lrV.pBits, lrV.Pitch, width / 2, height / 2);
的缓冲区吗?
答案 0 :(得分:1)
我找到了出路。
有AVCodecContext
的公共成员, get_buffer2 ,这是一个回调函数。在调用avcodec_decode_video2
时,将调用此回调函数,并且此回调函数负责将缓冲区和一些信息委托给AVFrame
,然后avcodec_decode_video2
将结果生成到{{1}的缓冲区}}
回调函数 get_buffer2 默认设置为AVFrame
。但是,我们可以将其覆盖为我们的私有函数。例如:
avcodec_default_get_buffer2
在解码之前,我们覆盖了回调函数:
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;
}
然后context->get_buffer2 = our_get_buffer;
会将结果生成到我们提供的缓冲区。
顺便说一下,对于经常在类中实现这些进程的C ++程序,我们可以先记录这个指针:
avcodec_decode_video2
将重写的回调函数定义为静态成员:
context->opaque = this;