2015-11-26 12044 views
0

问题: 为什么我su ...我的意思是,我的解码器是怎么回事?当我尝试获得多汁的输出数据时,它总是返回超时(-1)!MediaCodec解码器出现dequeueOutputBuffer调用问题(H.264)

让我开始说我已经通读了相关的线程,但仍然无法解决问题。我真的需要一些指导和帮助。好的,我正在做的是将AVC编码数据传递给我的解码器。编码器工作,从相机预览中提取数据,在传递到编码器之前,我将NV21转换为NV12。

编码器提供的第一个数据有codec-specific-data,我将它传递给ConfigureDecoder(ByteBuffer csd0, ByteBuffer csd1)函数来创建和配置解码器,它不会引发任何错误。

public void ConfigureDecoder(ByteBuffer csd0, ByteBuffer csd1) 
{ 
    try 
    { 
     decoder = MediaCodec.createDecoderByType(MIME_TYPE); 
    } 
    catch(IOException e) 
    { 
     Log.d(TAG, "Decoder codec creation failed: " + e.toString()); 
    } 

    MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, 320, 240); 
    format.setByteBuffer("csd-0", csd0); 
    format.setByteBuffer("csd-1", csd1); 
    decoder.configure(format, null, null, 0); 

    try 
    { 
     decoder.start(); 
     Log.d(TAG, "Decoder configured"); 
    } 
    catch(CodecException e) 
    { 
     Log.d(TAG, "Decoder config start failed: " + e.getDiagnosticInfo()); 
    } 
} 

下面的函数一旦编码器通知存在被编码的数据用(特定的编解码数据之后)被调用。首先,我得到一个可用的解码器输入缓冲区,如果成功,我用编码数据填充它(验证)并将其添加到解码器队列。然后,一切都变成地狱,我试图从解码器检索数据,使用dequeueOutputBuffer(bufferInfo, 0);,它总是返回-1。


public void offerDecoder(byte[] input, int offset, int size, long presentationTimeUs, int flags) 
{ 
    int inputBufIndex = decoder.dequeueInputBuffer(10000); 
    Log.d(TAG, "Decoder dequeueInputBuffer = " + inputBufIndex); 

    if(inputBufIndex >= 0) 
    { 
     try 
     { 
      // Get valid buffer and push into the decoder input buffer 
      ByteBuffer inputBuf = decoder.getInputBuffer(inputBufIndex); 
      inputBuf.clear(); 
      inputBuf = ByteBuffer.wrap(input); 
      decoder.queueInputBuffer(inputBufIndex, 0, size, presentationTimeUs, flags); 
     } 
     catch(MediaCodec.CodecException ce) 
     { 
      Log.d(TAG, "Decoder adding data error: " + ce.getDiagnosticInfo()); 
     } 
    } 

    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); 
    int outIndex = decoder.dequeueOutputBuffer(bufferInfo, 0); 
    Log.d(TAG, "Decoder dequeueOutputBuffer = " + outIndex); 

    switch(outIndex) 
    { 
     case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: 
      ByteBuffer outputBuffers = decoder.getOutputBuffer(outIndex); 
      Log.d(TAG, "Decoder dequeueOutputBuffer = INFO_OUTPUT_BUFFERS_CHANGED"); 
      break; 

     case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: 
      //MediaFormat bufferFormat = decoder.getOutputFormat(outIndex); 
      Log.d(TAG, "Decoder dequeueOutputBuffer = INFO_OUTPUT_FORMAT_CHANGED"); 
      break; 

     case MediaCodec.INFO_TRY_AGAIN_LATER: 
      //Total fail, something is really wrong if you are always receiving -1 from dequeueOutputBuffer 
      //Log.d(TAG, "Decoder dequeueOutputBuffer = INFO_TRY_AGAIN_LATER"); 
      break; 

     default: 
      Log.d(TAG, "Decoder out buffer info-->" + bufferInfo.offset + "--" + bufferInfo.size + "--" + bufferInfo.flags + "--" + bufferInfo.presentationTimeUs); 
      ByteBuffer buffer = decoder.getOutputBuffer(outIndex); 
      decoder.releaseOutputBuffer(outIndex, false); 
      break; 
    } 
} 

如果达到在后这点我很欣赏你的时间:)

回答

1

看来,这里的问题是,API给你错觉,以为解码将同步 - 这不是。

当你给解码器一个输入数据包时,它将开始解码它 - 现在你只在之后立即检查一次,当解码器返回-1表明它没有更多的输出(尚)。

您可以增加timeoutUs参数让它稍等一会儿,以查看解码器是否返回某些内容,或将其设置为-1以无限期等待。但是如果你总是等待每个输入数据包的输出,那么你的性能会非常差(并且在输入中断的情况下,你可能根本就没有得到任何输出)。您应该为解码器提供尽可能多的解码数据(直到dequeueInputBuffer指示当前没有输入缓存可用),并使用解码器提供的任何输出缓存。如果仅针对Android 5.0或更高版本是您的选项,则应查看回调API(MediaCodec.setCallback),这样可以更清楚地了解,无需轮询输出。

+0

IIRC,AVC编解码器在开始执行任何操作之前,都希望能提供四个访问单元。我预计这会因设备而异。 http://bigflake.com/mediacodec/ – fadden