Android MediaCodec解码H264原始帧 [英] Android MediaCodec decode h264 raw frame

查看:904
本文介绍了Android MediaCodec解码H264原始帧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Android MediaCodec API解码h264帧.我可以解码并渲染视图上的帧.我的问题是解码器会丢失很多帧,尤其是前几帧. DecodeMediaCodec.dequeueOutputBuffer()返回-1.大约150个h264帧,仅解码了43帧.我找不到问题所在.这是我的代码.

I am using Android MediaCodec API to decode h264 frames. I could decode and render the frames on the view. My problem is the decoder miss lots of frames,especially the first some frames. DecodeMediaCodec.dequeueOutputBuffer() return -1. aAbout 150 h264 frames,just decoded 43 frames. I can not find where the problem is. Here is my codes.

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

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

After decoder initial,I will start decoder thread.

 /**
 * 
 * @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.

Anybody knows why?I hope your help.My android device is nexus 7.

推荐答案

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

Getting -1 back from MediaCodec#dequeueOutputBuffer() is normal. It just means it doesn't have any output ready yet.

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

It's not the case that you hand MediaCodec a buffer of encoded data and immediately get a decoded buffer back. You hand it a buffer of data, which gets sent to the mediaserver process, which feeds it into the hardware AVC decoder, which may still be initializing or maybe just likes to sit on a few frames. When the decoding process completes, the decoded data gets passed back through mediaserver to your app process.

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

The trick is, the queueInputBuffer() call returns immediately. In normal operation the input side of the decoder will run several frames ahead of the output side. When you're done feeding input you set the end-of-stream flag, and when you see EOS set on the output you know you've reached the end.

您可以在 bigflake

You can find various working examples on bigflake and in Grafika. The DecodeEditEncodeTest and EncodeDecodeTest examples work exclusively with raw H.264, the others use MediaExtractor and MediaMuxer to handle MP4 file wrappers.

这篇关于Android MediaCodec解码H264原始帧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆