背景:
我已将 Android 的 MediaCodec 连接到 FFmpeg,用于混合 MediaMuxer 不支持的各种格式,包括rtmp://
通过.flv
容器输出。此类流式多路复用器需要更长且不可预测的 MediaCodec 输出缓冲区所有权,因为它们可能在任何数据包处理步骤上执行网络 I/O。对于我的视频流,我使用为 Surface 输入配置的 MediaCodec。为了将复用与编码分离,我通过一个处理程序将 MediaCodec 的 ByteBuffer 输出缓冲区排队到我的复用器。
.flv
如果我将输出复用到文件而不是 rtmp 端点,那么所有工作都非常出色。
问题:
当复用到rtmp://...
端点时,我注意到我的流应用程序立即开始阻止调用我eglSwapBuffers(mEGLDisplay, mEncodingEGLSurface)
在dequeueOutputBuffer()
复用队列中保留了几个 MediaCodec 输出缓冲区,因为 MediaCodec 似乎只锁定到 4 个输出缓冲区。
有什么技巧可以避免复制由返回MediaCodec#dequeueOutputBuffers
并立即调用的所有编码器输出releaseOutputBuffer(...)
?
我的项目的完整源代码可在Github上找到。具体见:
- AndroidEncoder.java:在音频和视频编码器之间具有共享行为的抽象编码器类:主要是 drainEncoder()。将数据写入
Muxer
实例。 - FFmpegMuxer.java:实现
Muxer
- 相机编码器.java。将相机帧发送到为视频编码配置的 AndroidEncoder 子类。
系统跟踪
这是一些 systrace 输出流式传输 720p @ 2Mbps 视频到 Zencoder。
解决了
复制并在 MediaCodec 编码器输出 ByteBuffer 可用时立即释放它们可以解决问题,而不会显着影响性能。我为每个复用器轨道回收了 ByteBuffer 副本ArrayDeque<ByteBuffer>
,这限制了分配的数量。