繁体   English   中英

Android MediaCodec 实时 h264 编码/解码延迟

[英]Android MediaCodec realtime h264 encoding/decoding latency

我正在使用 Android MediaCodec 并将其用于来自相机的实时 H264 编码和解码帧。 我以同步方式使用 MediaCodec 并将 output 渲染到解码器的表面并且一切正常,除了我有一个很长的实时延迟,它需要 1.5-2 秒,我很困惑为什么会这样。 我测量了编码和解码过程的总时间,它保持在 50-65 毫秒左右,所以我认为问题不在他们身上。 我试图更改编码器的配置但没有帮助,目前它的配置如下:

val formatEncoder = MediaFormat.createVideoFormat("video/avc", 1920, 1080)
formatEncoder.setInteger(MediaFormat.KEY_FRAME_RATE, 30)
formatEncoder.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5)
formatEncoder.setInteger(MediaFormat.KEY_BIT_RATE, 1920 * 1080)
formatEncoder.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
val encoder = MediaCodec.createEncoderByType("video/avc")
encoder.configure(formatEncoder, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
val inputSurface = encoder.createInputSurface() // I use it to send frames from camera to encoder
encoder.start()

更改解码器的配置也对我没有任何帮助,目前我是这样配置的:

val formatDecoder = MediaFormat.createVideoFormat("video/avc", 1920, 1080)
val decoder = MediaCodec.createDecoderByType("video/avc")
decoder.configure(formatDecoder , outputSurface, null, 0) // I use outputSurface to render decoded frames into it
decoder.start()

我使用以下超时来等待可用的编码器/解码器缓冲区我试图减少它们的值但它没有帮助我,我像这样离开它们:

var TIMEOUT_IN_BUFFER = 10000L // microseconds
var TIMEOUT_OUT_BUFFER = 10000L // microseconds

我还测量了消耗 inputSurface 一帧的时间,这次需要 0.03-0.05 毫秒,所以它不是瓶颈。 实际上我测量了所有可能出现瓶颈的地方,但我什么也没发现,我认为问题出在编码器或解码器本身或它们的配置中,或者我应该使用一些特殊的例程来发送帧到编码/解码..

我还尝试使用 HW 加速编解码器,这是唯一对我有帮助的东西,当我使用它时,延迟减少到大约 500-800 毫秒,但它仍然不适合我进行实时流式传输。

在我看来,编码器或解码器在开始在表面上显示它们之前会缓冲几帧,最终会导致延迟,如果确实如此,那么我该如何禁用缓冲或减少它的时间?

请帮助我,我在这个问题上坚持了大约半年,不知道如何减少延迟,我确信这是可能的,因为 Telegram、Viber、WhatsApp 等流行应用程序运行良好且没有延迟,所以这是什么这里的秘密?

更新 07.07.2021:

我仍然没有找到消除延迟的解决方案。 我尝试更改 h264 配置文件,增加和减少 I 帧间隔、比特率、帧率,但结果是一样的,唯一能稍微减少延迟的是——将分辨率从 1920x1080 降级到例如 640x480,但是这个“解决方案”不适合我,因为我想编码/解码分辨率为 1920x1080 的实时视频。

更新 08.07.2021:

我发现,如果我将 TIMEOUT_IN_BUFFER 和 TIMEOUT_OUT_BUFFER 的值从 10_000L 更改为 100_000L,它会稍微减少延迟,但会在开始编码/解码过程后显着增加显示第一帧的延迟。

您的编码器可能正在生成 B 帧——双线性插值帧。 它们提高了质量和延迟,非常适合电影。 但对低延迟应用程序没有好处。

  • 关键帧 = I(帧间)
  • 预测帧 = P(与先前帧的差异)
  • 插值帧 = B

包括 B 帧的帧序列可能如下所示:

IBBBPBBBPBBBPBBBI
         11111111
12345678901234567

编码器必须对每个 P 帧进行编码,而解码器必须在前面的 B 帧有意义之前对其进行解码。 所以在这个例子中,帧被乱序编码,如下所示:

1 5 2 3 4 9 6 7 8 13 10 11 12 17 17 13 14 15  

在这个例子中,直到编码器发送了第 5 帧,解码器才能处理第 2 帧。

另一方面,这个没有 B 帧的序列允许按顺序对帧进行编码和解码。

IPPPPPPPPPPIPPPPPPPPP

尝试使用受约束的基线配置文件设置。 它专为低延迟和低功耗使用而设计。 它抑制 B 帧。 我认为这行得通。

mediaFormat.setInteger(
        "profile",
         CodecProfileLevel.AVCProfileConstrainedBaseline); 

我相信 android h264 解码器有延迟(至少在我尝试过的大多数情况下)。 可能这就是 android 开发人员从 API 级别 30 中添加PARAMETER_KEY_LOW_LATENCY的原因。但是我可以通过再查询 Z78E6221F6393D1356681DB398F14CE6 来减少一些帧的延迟。 原因:不知道。 这只是无聊的试验和错误的结果

int inputIndex = m_codec.dequeueInputBuffer(-1);// Pass in -1 here bc we don't have a playback time reference

if (inputIndex >= 0) {
    ByteBuffer buffer;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        buffer = m_codec.getInputBuffer(inputIndex);
    } else {
        ByteBuffer[] bbuf = m_codec.getInputBuffers();
        buffer = bbuf[inputIndex];
    }
    buffer.put(frame);

    // tell the decoder to process the frame
    m_codec.queueInputBuffer(inputIndex, 0, frame.length, 0, 0);
}
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();

int outputIndex = m_codec.dequeueOutputBuffer(info, 0);
if (outputIndex >= 0) {
    m_codec.releaseOutputBuffer(outputIndex, true);
}
outputIndex = m_codec.dequeueOutputBuffer(info, 0);
if (outputIndex >= 0) {
    m_codec.releaseOutputBuffer(outputIndex, true);
}
outputIndex = m_codec.dequeueOutputBuffer(info, 0);
if (outputIndex >= 0) {
    m_codec.releaseOutputBuffer(outputIndex, true);
}

您需要为不同的 cpu 供应商配置自定义(或 KEY_LOW_LATENCY,如果支持)低延迟参数。 这是android电话的通病。

检查此代码https://github.com/moonlight-stream/moonlight-android/blob/master/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM