解码H264视频时,Android MediaCodec releaseOutputBuffer会抛出MediaCodec.CodecException

时间:2016-02-04 17:21:53

标签: android video decode mediacodec

我正在使用MediaCodec API来解码H264视频流,使用SurfaceView作为输出曲面。解码器配置成功,没有任何错误。当我尝试使用SurfaceView最终将解码的视频帧渲染到releaseOutputBuffer(bufferIndex, true)时,它会抛出MediaCodec.CodecException,但视频会正确呈现。

在异常对象上调用getDiagnosticInfo()getErrorCode()会返回错误代码-34,但我无法在文档中找到此错误代码的含义。关于何时抛出此异常,文档也非常不清楚。

之前是否有人遇到此异常/错误代码?我该如何解决这个问题?

PS:虽然视频效果很好,但每次releaseOutputBuffer(bufferIndex, true),电话都会抛出此异常。

2 个答案:

答案 0 :(得分:0)

Android media-codec非常依赖于设备供应商。三星是一个令人难以置信的问题,运行相同代码的其他设备运行正常。这是我过去6个月的生活。

尽管可能感觉不对,最好的方法是尝试+ catch +重试。 MediaCodec将有4个不同的地方会抛出异常:

  1. 配置 - NativeDecoder.Configure(...);
  2. 开始 - NativeDecoder.Start();
  3. 渲染输出 - NativeDecoder.ReleaseOutputBuffer(...);
  4. 输入 - codec.QueueInputBuffer(...);
  5. 注意:我的代码在Xamarin中,但调用与原始java非常接近。

    配置格式描述的方式也很重要。如果您未指定:

    ,则媒体编解码器可能会在NEXUS设备上崩溃
    formatDescription.SetInteger(MediaFormat.KeyMaxInputSize, currentPalette.Width * currentPalette.Height);
    

    当您发现任何异常时,您需要确保重置mediacodec。不幸的重置不适用于较旧的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,对视频来说是最稳定的。即使在屏幕上同时有多达21个并发视频。三星S4可以在4-6左右取决于分辨率/ fps,但像HTC这样的东西可以和Hudl一样工作。这是一个警醒,让我意识到三星设备实际上是在复制苹果设计和使用android-sdk,实际上在整个过程中打破了很多功能。

答案 1 :(得分:-1)

这很可能是您正在使用的编解码器的问题。尝试使用这样的东西

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

这可以通过确保完全支持您选择的编解码器来解决您的错误。