2014-01-17 191 views
8

我正在使用Android MediaCodec API来解码h264帧。我可以解码和渲染视图上的帧。我的问题是解码器错过了很多帧,尤其是第一些帧。 DecodeMediaCodec.dequeueOutputBuffer()返回-1。 a约150 h264帧,仅解码43帧。我找不到问题所在。这是我的代码。Android MediaCodec解码h264原始帧

/** 
* init decoder 
*/ 
private void initDecodeMediaCodec() 
{ 
    mDecodeMediaCodec = MediaCodec.createDecoderByType(MIME_TYPE); 
    MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, 
      VIDEO_WIDTH_640, 
      VIDEO_HEIGHT_480); 

    mDecodeMediaCodec.configure(format, 
      new Surface(mRemoteVideoView.getSurfaceTexture()), 
      null, 
      0); 
    mDecodeMediaCodec.start(); 
    mDecodeInputBuffers = mDecodeMediaCodec.getInputBuffers(); 
    System.out.println("decode-----" 
      + mDecodeMediaCodec.getCodecInfo().getName()); 
} 

解码器初始化后,我将启动解码器线程。

/** 
* 
* @param frameData 
*/ 
private void decode() 
{ 
    new Thread(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      while (true) 
      { 
       ByteBuffer decodeDataBuffer = null; 
       try 
       { 
        //take h264 frame from cache queue 
        decodeDataBuffer = decodeDataQuene.take(); 
       } 
       catch (InterruptedException e) 
       { 
        e.printStackTrace(); 
       } 


       BufferInfo info = new BufferInfo(); 
       int inputBufferIndex = mDecodeMediaCodec.dequeueInputBuffer(-1); 
       System.out.println("inputBufferIndex: " + inputBufferIndex); 
       if (inputBufferIndex >= 0) 
       { 
        ByteBuffer buffer = mDecodeInputBuffers[inputBufferIndex]; 
        buffer.clear(); 
        buffer.put(decodeDataBuffer.array()); 
        mDecodeMediaCodec.queueInputBuffer(inputBufferIndex, 
          0, 
          decodeDataBuffer.array().length, 
          0, 
          0); 
        decodeDataBuffer.clear(); 
        decodeDataBuffer = null; 
       } 

       int outputBufferIndex = mDecodeMediaCodec.dequeueOutputBuffer(info, 
         1000); 
       System.out.println("outputBufferIndex: " 
         + outputBufferIndex); 
       do 
       { 

        if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) 
        { 
         //no output available yet 
        } 
        else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) 
        { 
         //encodeOutputBuffers = mDecodeMediaCodec.getOutputBuffers(); 
        } 
        else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) 
        { 
         MediaFormat formats = mDecodeMediaCodec.getOutputFormat(); 
         //mediaformat changed 
        } 
        else if (outputBufferIndex < 0) 
        { 
         //unexpected result from encoder.dequeueOutputBuffer 
        } 
        else 
        { 
         mDecodeMediaCodec.releaseOutputBuffer(outputBufferIndex, 
           true); 

         outputBufferIndex = mDecodeMediaCodec.dequeueOutputBuffer(info, 
           0); 
         System.out.println("inner outputBufferIndex: " 
           + outputBufferIndex); 
        } 
       } while (outputBufferIndex > 0); 
      } 
     } 
    }).start(); 
} 

任何人都知道这是为什么呢?我希望你help.My Android设备的Nexus 7

回答

5

获得-1从MediaCodec#dequeueOutputBuffer()回是正常的。这仅表示它尚未准备好任何输出。

并非如此,您可以将MediaCodec缓冲区中的编码数据传回并立即获得解码缓冲区。您将数据缓冲区发送到mediaserver进程,该进程会将其馈送到硬件AVC解码器中,该解码器可能仍在初始化或可能只是坐在几个帧上。解码过程完成后,解码后的数据将通过mediaserver传回给您的应用程序进程。

诀窍是,queueInputBuffer()调用立即返回。在正常操作中,解码器的输入端将在输出端之前运行数帧。当您完成喂料输入时,您设置了流尾标志,并且当您在输出中看到EOS时,您知道您已达到最后。

您可以在bigflakeGrafika中找到各种工作示例。 DecodeEditEncodeTest和EncodeDecodeTest示例仅使用原始H.264,其他使用MediaExtractorMediaMuxer来处理MP4文件包装。

+0

我查看了您提供的资源,我对此有一些疑问。 ** 1)是否有任何方法可以让解码器快速解码帧?** ** 2)我应该将第一个编码帧的cds-0添加到解码器格式吗?** ** 3)PresentationTime是必须的吗?** –

+0

(1)您可以通过提前配置和启动解码器来节省一些时间。我没有尝试过。你看到多少延迟? (2)您可以将CSD添加到“MediaFormat”中,或者将其作为第一帧与“CODEC_CONFIG”标志设置一起提交。不要这样做。 (3)我认为编解码器在解码时没有注意PTS。 (虽然编码时它*是重要的)。如果你从源头获得时间戳,尽管保留它们是一个不错的主意 - 例如以防你的视频源不能以恒定速率提供帧。 – fadden

+1

我的Nexus 7上的延迟大约是19帧,而我的三星S3上有6帧。达赖相对稳定。它似乎与硬件有关系,但我不确定。 –