2

背景:

我已将 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>,这限制了分配的数量。

4

1 回答 1

3

不幸的是,大多数 Android 手机不支持这种用例。MediaCodec 只是编解码器供应商在设备上使用的 OMX IL API 的抽象。对于给定的配置,供应商编解码器需要一定数量的输入和输出缓冲区。

虽然理论上,让一个输出缓冲区与编码器一起排队就足够了,但很多时候供应商编解码器不支持这种做法,因为它会导致编码性能降低;因此编解码器停止。这在输入缓冲区中更为普遍。

对于为 MediaCodec 实例分配的输入/输出缓冲区的数量没有应用程序控制 - Android 尝试分配所需的最小缓冲区数量,以节省内存。因此,您唯一的选择是复制输出缓冲区。虽然这并不理想,但编码缓冲区往往相当小。

于 2014-02-12T18:30:23.093 回答