【问题标题】:Android MediaCodec decode h264 raw frameAndroid MediaCodec 解码 h264 原始帧
【发布时间】:2014-02-06 13:37:42
【问题描述】:

我正在使用 Android MediaCodec API 来解码 h264 帧。我可以解码和渲染视图上的帧。我的问题是解码器错过了很多帧,尤其是前几帧。 DecodeMediaCodec.dequeueOutputBuffer() 返回 -1。 a约150个h264帧,刚解码43帧。我找不到问题出在哪里。这是我的代码。

 /**
 * 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();
}

有人知道为什么吗?我希望你的帮助。我的 android 设备是 nexus 7。

【问题讨论】:

  • 我知道这是一个非常古老的线程,但介意分享您的代码吗?我正在尝试从实时流中获取原始 h264 帧并将其显示在我的 android 应用程序中。

标签: android decode android-mediacodec


【解决方案1】:

MediaCodec#dequeueOutputBuffer() 返回 -1 是正常的。这只是意味着它还没有准备好任何输出。

情况并非如此,您将一个编码数据缓冲区交给MediaCodec,然后立即取回一个解码缓冲区。你给它一个数据缓冲区,它被发送到mediaserver 进程,该进程将其馈送到硬件 AVC 解码器,它可能仍在初始化,或者可能只是喜欢坐在几帧上。解码过程完成后,解码后的数据会通过mediaserver 传递回您的应用进程。

诀窍是,queueInputBuffer() 调用会立即返回。在正常操作中,解码器的输入端将在输出端之前运行几帧。当您完成输入输入时,您设置了流结束标志,当您看到输出上设置了 EOS 时,您就知道您已经到达终点。

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

【讨论】:

  • 我已经查看了您给定的资源,对此我有一些疑问。 1) 有什么方法可以让解码器快速解码帧? 2) 我应该在解码器格式中添加第一个编码帧 cds-0 吗? 3)PresentationTime是必须的吗?
  • (1) 您可以通过提前配置和启动解码器来节省一些时间。我没有尝试过它。你看到多少延迟? (2) 您可以将 CSD 添加到 MediaFormat 或将其作为设置了 CODEC_CONFIG 标志的第一帧提交。不要两者都做。 (3)我认为编解码器在解码时没有注意PTS。 (尽管在编码时它 很重要。)如果您从源获取时间戳,那么保留它们是一个好主意 - 例如以防您的视频源没有以恒定速率提供帧。
  • Nexus 7 的延迟约为 19 帧,三星 s3 的延迟为 6 帧。当天相对稳定。好像和硬件有关系,但我不确定。
  • @fadden 你介意看看我的问题吗 - stackoverflow.com/q/50817767/8199772
猜你喜欢
  • 1970-01-01
  • 2016-05-27
  • 2013-12-03
  • 1970-01-01
  • 2017-12-16
  • 2013-04-25
  • 1970-01-01
  • 2012-10-29
  • 2018-10-17
相关资源
最近更新 更多