FFMPEG:在解码视频时,可以生成结果给用户提供的缓冲区吗?

时间:2015-02-05 09:09:15

标签: c++ video ffmpeg directx

在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); 的缓冲区吗?

1 个答案:

答案 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;