6

我正在尝试优化一个播放视频的软件,它在内部使用 FFmpeg 库进行解码。我们发现,在一些大型(4K、60fps)视频中,解码一帧的时间有时比显示该帧的时间要长;可悲的是,由于问题域,简单地缓冲/跳过帧不是一种选择。

但是,似乎 FFmpeg 可执行文件能够以大约 2 倍的速度很好地解码有问题的视频,所以我一直在努力找出我们做错了什么。

我为测试编写了一个非常精简的解码器程序;源代码在这里(大约 200 行)。从分析来看,解码过程中的一个主要瓶颈似乎是avcodec_send_packet()函数,每次调用最多可能需要 50 毫秒。但是,在 FFmpeg 中测量相同的调用会显示出奇怪的行为:

是的,您可以嵌入图像

(这些是解码 4K 25fps VP9 编码视频时,每次调用 avcodec_send_packet() 所需的时间(以毫秒为单位。)

基本上,当 FFmpeg 使用这个函数时,似乎只需要花费任何时间来完成每 N 次调用,其中 N 是用于解码的线程数。但是,我的测试解码器和实际产品都使用 4 个线程进行解码,这不会发生;使用基于帧的线程时,测试解码器的行为类似于 FFmpeg,仅使用 1 个线程。这似乎表明我们根本没有使用多线程,但我们仍然看到通过使用更多线程来提高性能。

FFmpeg 的结果平均比我们的解码器快两倍,所以很明显我们做错了什么。我一直在阅读 FFmpeg 的源代码以试图找到任何线索,但到目前为止我还没有找到。

我的问题是:FFmpeg 在这里做什么而我们不是?或者,我们如何提高解码器的性能?

任何帮助是极大的赞赏。

4

2 回答 2

3

我面临着同样的问题。我花了很长时间才想出一个解决方案,我想在这里分享以供将来参考:

为解码器启用多线程。默认情况下,解码器只使用一个线程,取决于解码器,多线程可以大大加快解码速度。

假设你有AVFormatContext *format_ctx一个匹配的编解码器AVCodec* codecAVCodecContext* codec_ctx(分配使用avcodec_alloc_context3)。

打开编解码器上下文(使用avcodec_open2)之前,您可以配置多线程。检查编解码器的功能以确定可以使用哪种多线程:

// set codec to automatically determine how many threads suits best for the decoding job
codec_ctx->thread_count = 0;

if (codec->capabilities | AV_CODEC_CAP_FRAME_THREADS)
   codec_ctx->thread_type = FF_THREAD_FRAME;
else if (codec->capabilities | AV_CODEC_CAP_SLICE_THREADS)
   codec_ctx->thread_type = FF_THREAD_SLICE;
else
   codec_ctx->thread_count = 1; //don't use multithreading

我发现的另一个加速如下:继续向解码器发送数据包(这就是avcodec_send_packet()正在做的事情),直到你得到AVERROR(EAGAIN)返回值。这意味着内部解码器缓冲区已满,您首先需要收集解码帧(但请记住在解码器再次为空后再次发送最后一个数据包)。现在您可以收集解码的帧,avcodec_receive_frame直到您AVERROR(EAGAIN)再次获得。一些解码器在有多个帧排队等待解码时工作得更快(这就是解码器在codec_ctx->thread_type = FF_THREAD_FRAME设置时所做的事情)。

于 2021-09-02T07:33:35.747 回答
0

avcodec_send_packet()并且avcodec_receive_frame()是包装函数,最重要的是调用所选编解码器的解码函数并返回解码帧(或错误)。

尝试调整编解码器选项,例如,低延迟可能无法满足您的需求。有时旧的 api(我相信它仍然存在)avcodec_decode_video2()优于新的,你也可以尝试一下。

于 2019-03-18T10:28:41.273 回答