2016-02-04 426 views
0

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

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

有没有人遇到过这个异常/错误代码?我怎样才能解决这个问题?

PS:虽然视频可以正常工作,但每次调用releaseOutputBuffer(bufferIndex, true),时都会引发这种怀疑。

回答

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

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

+0

这不能解决问题。 –

+0

是否有任何可以从错误代码-34推断出来的东西? –

+0

不幸的是,我不能找到。您可能需要查看MediaCodec的源代码,以查找该代码中抛出的-34。 – Devsil

0

Android媒体编解码器非常依赖设备供应商。三星是令人难以置信的问题,运行相同的代码的其他设备将运行良好。这是我过去6个月的生活。

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

  1. 配置 - NativeDecoder.Configure(...);
  2. 开始 - NativeDecoder.Start();
  3. 渲染输出 - NativeDecoder.ReleaseOutputBuffer(...);
  4. Input - codec.QueueInputBuffer(...);

注:我的代码是在Xamarin中,但调用映射非常接近原始的Java。

配置格式描述的方式也很重要。该mediacodec会崩溃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个并发视频。根据分辨率/ fps,Samsung S4可以达到4-6左右,但像HTC这样的产品可以和Hudl一样工作。它是一个唤醒电话,让我意识到三星设备是从字面上抄袭苹果设计,并与android-sdk混合在一起,实际上打破了许多功能。

+0

@redbain我同意你的观察。三星通常是最不稳定的。他们彻底打破了Android 5.0中的OpenMAX实现。 –

+0

在我的情况下MediaCodec异常是在每个ReleaseOutputBuffer调用中引发的。所以我不认为每帧都是一个选项后重新启动解码器。 –

+0

@ nangal.vivek是否解析NALU细分?您必须在您的信息流中解析我们的nalu细分,并确保它们采用附件格式。它是0x00,0x00,0x00,0x01,。可能是问题。我不知道在我的情况下,我们是否可以使用媒体提取器来解析实时网络提要​​。 – redbrain