繁体   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