简体   繁体   English

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

[英]Android MediaCodec realtime h264 encoding/decoding latency

I'm working with Android MediaCodec and use it for a realtime H264 encoding and decoding frames from camera.我正在使用 Android MediaCodec 并将其用于来自相机的实时 H264 编码和解码帧。 I use MediaCodec in synchronous manner and render the output to the Surface of decoder and everething works fine except that I have a long latency from a realtime, it takes 1.5-2 seconds and I'm very confused why is it so.我以同步方式使用 MediaCodec 并将 output 渲染到解码器的表面并且一切正常,除了我有一个很长的实时延迟,它需要 1.5-2 秒,我很困惑为什么会这样。 I measured a total time of encoding and decoding processes and it keeps around 50-65 milliseconds so I think the problem isn't in them.我测量了编码和解码过程的总时间,它保持在 50-65 毫秒左右,所以我认为问题不在他们身上。 I tried to change the configuration of the encoder but it didn't help and currently it configured like this:我试图更改编码器的配置但没有帮助,目前它的配置如下:

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()

Changing the configuration of the decoder also didn't help me at all and currently I configured it like this:更改解码器的配置也对我没有任何帮助,目前我是这样配置的:

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()

I use the following timeouts for waiting for available encoder/decoder buffers I tried to reduce their values but it didn't help me and I left them like this:我使用以下超时来等待可用的编码器/解码器缓冲区我试图减少它们的值但它没有帮助我,我像这样离开它们:

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

Also I measured the time of consuming the inputSurface a frame and this time takes 0.03-0.05 milliseconds so it isn't a bottleneck.我还测量了消耗 inputSurface 一帧的时间,这次需要 0.03-0.05 毫秒,所以它不是瓶颈。 Actually I measured all the places where a bottleneck could be, but I wasn't found anything and I think the problem is in the encoder or decoder itself or in their configurations, or maybe I should use some special routine for sending frames to encoding/decoding..实际上我测量了所有可能出现瓶颈的地方,但我什么也没发现,我认为问题出在编码器或解码器本身或它们的配置中,或者我应该使用一些特殊的例程来发送帧到编码/解码..

I also tried to use HW accelerated codec and it's the only thing that helped me, when I use it the latency reduces to ~ 500-800 milliseconds but it still doesn't fit me for a realtime streaming.我还尝试使用 HW 加速编解码器,这是唯一对我有帮助的东西,当我使用它时,延迟减少到大约 500-800 毫秒,但它仍然不适合我进行实时流式传输。

It seems to me that the encoder or decoder buffers several frames before start displaying them on the surface and eventually it leads to the latency and if it really so then how can I disable bufferization or reduce the time of it?在我看来,编码器或解码器在开始在表面上显示它们之前会缓冲几帧,最终会导致延迟,如果确实如此,那么我该如何禁用缓冲或减少它的时间?

Please help me I'm stucking on this problem for about half a year and have no idea how to reduce the latency, I'm sure that it's possible because popular apps like Telegram, Viber, WhatsApp etc. work fine and without latency so what's the secret here?请帮助我,我在这个问题上坚持了大约半年,不知道如何减少延迟,我确信这是可能的,因为 Telegram、Viber、WhatsApp 等流行应用程序运行良好且没有延迟,所以这是什么这里的秘密?

UPD 07.07.2021:更新 07.07.2021:

I still haven't found a solution to get rid of the latency.我仍然没有找到消除延迟的解决方案。 I've tried to change h264 profiles, increase and decrease I-frame inteval, bitrate, framerate, but result the same, the only thing that hepls a little to reduce the latency - downgrade the resolution from 1920x1080 to eg 640x480, but this "solution" doesn't suit me because I want to encode/decode a realtime video with 1920x1080 resolution.我尝试更改 h264 配置文件,增加和减少 I 帧间隔、比特率、帧率,但结果是一样的,唯一能稍微减少延迟的是——将分辨率从 1920x1080 降级到例如 640x480,但是这个“解决方案”不适合我,因为我想编码/解码分辨率为 1920x1080 的实时视频。

UPD 08.07.2021:更新 08.07.2021:

I found out that if I change the values of TIMEOUT_IN_BUFFER and TIMEOUT_OUT_BUFFER from 10_000L to 100_000L it decreases the latency a bit but increases the delay of showing the first frame quite a lot after start encoding/decoding process.我发现,如果我将 TIMEOUT_IN_BUFFER 和 TIMEOUT_OUT_BUFFER 的值从 10_000L 更改为 100_000L,它会稍微减少延迟,但会在开始编码/解码过程后显着增加显示第一帧的延迟。

It's possible your encoder is producing B frames -- bilinear interpolation frames.您的编码器可能正在生成 B 帧——双线性插值帧。 They increase quality and latency, and are great for movies.它们提高了质量和延迟,非常适合电影。 But no good for low-latency applications.但对低延迟应用程序没有好处。

  • Key frames = I (interframes)关键帧 = I(帧间)
  • Predicted frames = P (difference from previous frames)预测帧 = P(与先前帧的差异)
  • Interpolated frames = B插值帧 = B

A sequence of frames including B frames might look like this:包括 B 帧的帧序列可能如下所示:

IBBBPBBBPBBBPBBBI
         11111111
12345678901234567

The encoder must encode each P frame, and the decoder must decode it, before the preceding B frames make any sense.编码器必须对每个 P 帧进行编码,而解码器必须在前面的 B 帧有意义之前对其进行解码。 So in this example the frames get encoded out of order like this:所以在这个例子中,帧被乱序编码,如下所示:

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

In this example the decoder can't handle frame 2 until the encoder has sent frame 5.在这个例子中,直到编码器发送了第 5 帧,解码器才能处理第 2 帧。

On the other hand, this sequence without B frames allows coding and decoding the frames in order.另一方面,这个没有 B 帧的序列允许按顺序对帧进行编码和解码。

IPPPPPPPPPPIPPPPPPPPP

Try using the Constrained Baseline Profile setting.尝试使用受约束的基线配置文件设置。 It's designed for low latency and low power use.它专为低延迟和低功耗使用而设计。 It suppresses B frames.它抑制 B 帧。 I think this works.我认为这行得通。

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

I believe android h264 decoder have latency (at-least in most cases i've tried).我相信 android h264 解码器有延迟(至少在我尝试过的大多数情况下)。 Probably that's why android developers added PARAMETER_KEY_LOW_LATENCY from API level 30. However I could decrease the delay some frames by querying for the output some more times.可能这就是 android 开发人员从 API 级别 30 中添加PARAMETER_KEY_LOW_LATENCY的原因。但是我可以通过再查询 Z78E6221F6393D1356681DB398F14CE6 来减少一些帧的延迟。 Reason: no idea.原因:不知道。 It's just result of boring trial and errors这只是无聊的试验和错误的结果

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);
}

You need to configure customized(or KEY_LOW_LATENCY if it is supported) low latency parameters for different cpu venders.您需要为不同的 cpu 供应商配置自定义(或 KEY_LOW_LATENCY,如果支持)低延迟参数。 It is a common problem for android phone.这是android电话的通病。

Check this code https://github.com/moonlight-stream/moonlight-android/blob/master/app/src/main/java/com/limelight/binding/video/MediaCodecHelper.java检查此代码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