MediaCodec解码器与dequeueOutputBuffer调用(H.264)一起出现问题

时间:2015-11-26 01:19:23

标签: encoding h.264 mediacodec

问题: 为什么我...我的意思是,我的解码器发生了什么?当我试图获得丰富的输出数据时,它总是返回超时(-1)!

首先我要说的是我已经阅读了相关主题,但仍然无法解决问题。我真的需要一些指导和帮助。好的,我正在做的是将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;
    }
}

如果你在帖子中达到这一点,我真的很感谢你的时间:)

2 个答案:

答案 0 :(得分:1)

这里的问题似乎是API让你觉得解码是同步的 - 它不是。

当你给解码器一个输入数据包时,它会开始对它进行解码 - 现在你只需要立即检查一次,当解码器返回-1时表示它还没有任何输出(还有)。

您可以增加timeoutUs参数以使其等待一段时间以查看解码器是否返回某些内容,或将其设置为-1以无限期地等待。

但是如果你总是等待每个输入数据包的输出,你会得到相当糟糕的性能(如果输入中断,你可能根本得不到任何输出);您应该为解码器提供迄今为止要解码的数据(直到dequeueInputBuffer指示此时没有可用的输入缓冲区),并使用解码器提供的任何输出缓冲区。如果仅针对Android 5.0及更高版本定位是您的选项,您应该查看回调API(MediaCodec.setCallback),这更加清晰,无需轮询输出。

答案 1 :(得分:0)

我也面临同样的问题,解决方案就是从代码中删除以下行,

format.setByteBuffer("csd-0", csd0);
format.setByteBuffer("csd-1", csd1);