multithreading - FFmpeg 对 avcodec_send_packet() 做了什么?

标签 multithreading performance video ffmpeg avcodec

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

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

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

Yes, you can embed images

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

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

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

我的问题是:FFmpeg 在这里做了哪些我们没有做的事情?或者,我们如何提高解码器的性能?

非常感谢任何帮助。

最佳答案

我遇到了同样的问题。我花了很长时间才想出一个解决方案,我想在这里分享以供将来引用:

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

假设你有 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 时所做的事情)。

关于multithreading - FFmpeg 对 avcodec_send_packet() 做了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55186822/

相关文章:

java - 何时适用于使用 CopyOnWriteArrayList

java - Java线程执行单条指令是基于 native CPU还是字节码

C++ 等待线程退出

shell - youtube-dl 速率限制下载速度和自动恢复下载

ios - AVExportSession 在后台运行

javascript - HTML5 视频在 IE9 RC 中失败,但在 IE9 Beta 中失败

java - 从两个单独的传入请求注入(inject)数据

regex - 使用正则表达式过滤器在 MongoDB 中进行 Count() 查询 : slow performance

bash - 通过 Bash 文件中的 for-loop 运行脚本是否强制它们是单线程的?

python - 如何避免将重复项插入数据库的最有效方法?