簡體   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