用于RTMP流的MediaCodec编码器输出缓冲区的扩展客户端所有权

时间:2014-02-11 22:55:05

标签: android ffmpeg rtmp mediacodec mediamuxer

背景

我已将Android的MediaCodec连接到FFmpeg,以便对MediaMuxer不支持的各种格式进行多路复用,包括通过rtmp://容器输出.flv。这样的流式复用器需要更长,不可预测的MediaCodec输出缓冲器的所有权,因为它们可以在任何数据包处理步骤上执行网络I / O.对于我的视频流,我正在使用为Surface输入配置的MediaCodec。要将muxing与编码分离,我将MediaCodec的ByteBuffer输出缓冲区通过Handler排队到我的muxer。

如果我将.flv输出复用到文件而不是rtmp端点,那么所有工作都很出色。

问题:

当复用到rtmp://...端点时,我注意到我的流媒体应用程序在eglSwapBuffers(mEGLDisplay, mEncodingEGLSurface)处于dequeueOutputBuffer()的调用时开始阻止一旦我在我的多路复用队列中保留了几个MediaCodec输出缓冲区MediaCodec似乎只锁定了4个输出缓冲区。

避免复制MediaCodec#dequeueOutputBuffers返回的所有编码器输出并立即调用releaseOutputBuffer(...)的任何技巧?

我的项目的完整资源可在Github上找到。具体来说,请参阅:

  • AndroidEncoder.java:抽象编码器类,在音频和视频编码器之间具有共享行为:主要是drainEncoder()。将数据写入Muxer实例。
  • FFmpegMuxer.java:实施Muxer
  • CameraEncoder.java。将相机帧发送到为视频编码配置的AndroidEncoder子类。

Systrace

Systrace output

这是一些systrace输出流720p @ 2Mbps视频到Zencoder。

解决

复制然后释放MediaCodec编码器输出ByteBuffers在它们可用时解决问题而不会显着影响性能。我为每个复用器轨道在ArrayDeque<ByteBuffer>中回收ByteBuffer副本,这限制了分配的数量。

1 个答案:

答案 0 :(得分:3)

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

虽然理论上说,将一个与编码器排队的输出缓冲区应该足够,但很多时候供应商编解码器不支持这种情况,因为它会导致编码性能降低;因此编解码器停滞不前。输入缓冲区更为普遍。

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