簡體   English   中英

解碼H264視頻時Android MediaCodec releaseOutputBuffer拋出MediaCodec.CodecException

[英]Android MediaCodec releaseOutputBuffer throws MediaCodec.CodecException when decoding H264 video

我正在使用MediaCodec API 使用SurfaceView作為輸出表面解碼 H264 視頻流。 解碼器配置成功,沒有任何錯誤。 當我嘗試最終使用releaseOutputBuffer(bufferIndex, true)將解碼的視頻幀渲染到SurfaceView ,它會拋出MediaCodec.CodecException ,但是視頻渲染正確。

在異常對象上調用getDiagnosticInfo()getErrorCode()返回 -34 的錯誤代碼,但我在文檔中找不到此錯誤代碼的含義。 文檔也非常不清楚何時拋出此異常。

有沒有人遇到過這個異常/錯誤代碼? 我怎樣才能解決這個問題?

PS:雖然視頻工作正常,但在每個releaseOutputBuffer(bufferIndex, true),調用時都會拋出這個異常。

Android 媒體編解碼器非常依賴於設備供應商。 三星的問題令人難以置信,其他運行相同代碼的設備也能正常運行。 這就是我過去 6 個月的生活。

盡管可能會感覺不對,但最好的方法是嘗試 + 捕獲 + 重試。 MediaCodec 將在 4 個不同的地方拋出異常:

  1. 配置 - NativeDecoder.Configure(...);
  2. 開始 - NativeDecoder.Start();
  3. 渲染輸出 - NativeDecoder.ReleaseOutputBuffer(...);
  4. 輸入 - codec.QueueInputBuffer(...);

注意:我的代碼在 Xamarin 中,但調用非常接近原始 Java。

您配置格式描述的方式也很重要。 如果您不指定,媒體編解碼器可能會在 NEXUS 設備上崩潰:

formatDescription.SetInteger(MediaFormat.KeyMaxInputSize, currentPalette.Width * currentPalette.Height);

當您捕獲任何異常時,您需要確保媒體編解碼器已重置。 不幸的是,較舊的 api 級別無法使用重置,但您可以使用以下方法模擬相同的效果:

    #region Close + Release Native Decoder

    void StopAndReleaseNativeDecoder() {
        FlushNativeDecoder();
        StopNativeDecoder();
        ReleaseNativeDecoder();
    }

    void FlushNativeDecoder() {
        if (NativeDecoder != null) {
            try {
                NativeDecoder.Flush();
            } catch {
                // ignore
            }
        }
    }

    void StopNativeDecoder() {
        if (NativeDecoder != null) {
            try {
                NativeDecoder.Stop();
            } catch {
                // ignore
            }
        }
    }

    void ReleaseNativeDecoder() {
        while (NativeDecoder != null) {
            try {
                NativeDecoder.Release();
            } catch {
                // ignore
            } finally {
                NativeDecoder = null;
            }
        }
    }

    #endregion

在傳遞新輸入時捕獲錯誤后,您可以檢查:

if (!DroidDecoder.IsRunning && streamView != null && streamView.VideoLayer.IsAvailable) {
        DroidDecoder.StartDecoder(streamView.VideoLayer.SurfaceTexture);
}

DroidDecoder.DecodeH264FrameBuffer(payload, payloadSize, frameDuration, presentationTime, isKeyFrame);

渲染到紋理視圖似乎是目前最穩定的選項。 但是設備碎片化確實在這方面傷害了android。 我們發現更便宜的設備(例如 Tesco Hudl)對於視頻來說是最穩定的。 甚至 1 次屏幕上最多可同時顯示 21 個視頻。 三星 S4 可以達到 4-6 左右,具體取決於分辨率/fps,但像 HTC 這樣的東西可以像 Hudl 一樣工作。 它敲響了警鍾,讓我意識到三星設備實際上是在復制蘋果設計並使用 android-sdk,實際上在此過程中破壞了許多功能。

這很可能是您使用的編解碼器的問題。 嘗試使用這樣的東西

private static MediaCodecInfo selectCodec(String mime){
    int numCodecs = MediaCodecList.getCodecCount();

    for(int i = 0; i < numCodecs;  i++){
        MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
        if(!codecInfo.isEncoder()){
            continue;
        }

        String[] types = codecInfo.getSupportedTypes();
        for(int j = 0; j < types.length; j++){
            if(types[j].equalsIgnoreCase(mime)){
                return codecInfo;
            }
        }
    }
    return null;
}

然后設置您的編碼器:

MediaCodecInfo codecInfo = selectCodec(MIME_TYPE);
mEncoder = MediaCodec.createCodecByName(codecInfo.getName());

這可以通過確保您選擇的編解碼器得到完全支持來解決您的錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM