Jim*_*Jim 7 video performance multithreading ffmpeg avcodec
我正在尝试优化一个用于播放视频的软件,该软件内部使用 FFmpeg 库进行解码。我们发现,在某些大型(4K、60fps)视频中,有时解码帧所需的时间比该帧应显示的时间要长;遗憾的是,由于问题域的原因,简单地缓冲/跳过帧不是一种选择。
然而,FFmpeg 可执行文件似乎能够以大约 2 倍的速度很好地解码有问题的视频,因此我一直在努力找出我们做错了什么。
我已经编写了一个非常精简的解码器程序用于测试;源码在这里(大约200行)。从分析来看,解码过程中的一个主要瓶颈似乎是函数avcodec_send_packet(),每次调用最多可能需要 50 毫秒。然而,在 FFmpeg 中测量相同的调用会显示出奇怪的行为:

(这些是解码 4K 25fps VP9 编码视频时每次调用 avcodec_send_packet() 所需的时间(以毫秒为单位)。)
基本上,当 FFmpeg 使用此函数时,似乎只需要任意时间即可完成每 N 个调用,其中 N 是用于解码的线程数。然而,我的测试解码器和实际产品都使用4个线程进行解码,并且不会发生这种情况;当使用基于帧的线程时,测试解码器的行为类似于仅使用 1 个线程的 FFmpeg。这似乎表明我们根本没有使用多线程,但通过使用更多线程我们仍然看到了性能的改进。
FFmpeg 的结果平均起来大约是我们解码器的两倍,所以显然我们做错了一些事情。我一直在阅读 FFmpeg 的源代码,试图找到任何线索,但到目前为止我还没有找到任何线索。
我的问题是:FFmpeg 在这里做什么而我们没有做什么?或者,我们如何提高解码器的性能?
任何帮助是极大的赞赏。
我面临着同样的问题。我花了很长时间才找到一个解决方案,我想在这里分享以供将来参考:
为解码器启用多线程。默认情况下,解码器仅使用一个线程,根据解码器的不同,多线程可以极大地加快解码速度。
假设您有AVFormatContext *format_ctx、匹配的编解码器AVCodec* codec和AVCodecContext* 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
Run Code Online (Sandbox Code Playgroud)
我发现的另一个加速方法如下:继续向解码器发送数据包(这就是avcodec_send_packet()正在做的事情),直到获得AVERROR(EAGAIN)返回值。这意味着内部解码器缓冲区已满,您首先需要收集解码的帧(但请记住在解码器再次为空后再次发送最后一个数据包)。avcodec_receive_frame现在您可以使用直到再次获得来收集解码的帧AVERROR(EAGAIN)。当一些解码器有多个帧排队等待解码时,它们的工作速度会更快(这就是解码器在codec_ctx->thread_type = FF_THREAD_FRAME设置时所做的事情)。
avcodec_send_packet()包装avcodec_receive_frame()函数最重要的事情是调用选定编解码器的解码函数并返回解码帧(或错误)。
尝试调整编解码器选项,例如,低延迟可能无法满足您的需求。有时旧的 api(我相信它仍然存在)avcodec_decode_video2()比新的 api 表现更好,你也可以尝试一下。
| 归档时间: |
|
| 查看次数: |
1977 次 |
| 最近记录: |