使用MediaCodec解码h.264流

时间:2014-12-19 15:01:59

标签: android video-streaming h.264 mediacodec decoder

对于我的Quadcopter项目,我试图在我的Android手机上显示原始的H.264流。输入流来自TCP连接 我做了一些关于解码器如何工作的研究,并创建了以下解码器线程 SPS和PPS变量是从另一个函数中的数据中检索出来的,这应该是有效的,因为我从工作代码中复制了它。

private class PlayerThread extends Thread {
    private MediaCodec decoder;
    private Surface surface;

    public PlayerThread(Surface surface) {
        this.surface = surface;
    }

    @Override
    public void run() 
    {
        while(SPS == null || PPS == null || SPS.length == 0 || PPS.length == 0)
        {
            try 
            {
                Log.e("EncodeDecode", "DECODER_THREAD:: sps,pps not ready yet");
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();

            }
        }

        Log.d("EncodeDecode", "DECODER_THREAD:: sps,pps READY");


            decoder = MediaCodec.createDecoderByType("video/avc");
            MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 640, 480);
            mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(SPS));
            mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(PPS));
            decoder.configure(mediaFormat, surface /* surface */, null /* crypto */, 0 /* flags */);


        if (decoder == null) 
        {
            Log.e("DecodeActivity", "DECODER_THREAD:: Can't find video info!");
            return;
        }

        decoder.start();
        Log.d("EncodeDecode", "DECODER_THREAD:: decoder.start() called");

        ByteBuffer[] inputBuffers = decoder.getInputBuffers();
        ByteBuffer[] outputBuffers = decoder.getOutputBuffers();


        int i = 0;
        while(!Thread.interrupted())
        {
            Frame currentFrame = null;
            try 
            {
                Log.d("EncodeDecode", "DECODER_THREAD:: calling queue.take(), if there is no frame in the queue it will wait");
                currentFrame = queue.take();
            } 
            catch (InterruptedException e) 
            {
                Log.e("EncodeDecode","DECODER_THREAD:: interrupted while PlayerThread was waiting for the next frame");
                e.printStackTrace();
            }

            if(currentFrame == null)
                Log.e("EncodeDecode","DECODER_THREAD:: null frame dequeued");
            else
                Log.d("EncodeDecode","DECODER_THREAD:: " + currentFrame.id + " no frame dequeued");

            if(currentFrame != null && currentFrame.frameData != null && currentFrame.frameData.length != 0)
            {
                Log.d("EncodeDecode", "DECODER_THREAD:: decoding frame no: " + i + " , dataLength = " + currentFrame.frameData.length);

                int inIndex = 0; 
                while ((inIndex = decoder.dequeueInputBuffer(1)) < 0)
                    ;

                if (inIndex >= 0) 
                {
                    Log.d("EncodeDecode", "DECODER_THREAD:: sample size: " + currentFrame.frameData.length);

                    ByteBuffer buffer = inputBuffers[inIndex];
                    buffer.clear();
                    buffer.put(currentFrame.frameData);
                    decoder.queueInputBuffer(inIndex, 0, currentFrame.frameData.length, 33, 0);

                    BufferInfo info = new BufferInfo();
                    int outIndex = decoder.dequeueOutputBuffer(info, 100000);

                    switch (outIndex) 
                    {
                    case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                        Log.e("EncodeDecode", "DECODER_THREAD:: INFO_OUTPUT_BUFFERS_CHANGED");
                        outputBuffers = decoder.getOutputBuffers();
                        break;
                    case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                        Log.e("EncodeDecode", "DECODER_THREAD:: New format " + decoder.getOutputFormat());

                        break;
                    case MediaCodec.INFO_TRY_AGAIN_LATER:
                        Log.e("EncodeDecode", "DECODER_THREAD:: dequeueOutputBuffer timed out!");
                        break;
                    default:
                        Log.d("EncodeDecode", "DECODER_THREAD:: decoded SUCCESSFULLY!!!");
                        ByteBuffer outbuffer = outputBuffers[outIndex];
                        decoder.releaseOutputBuffer(outIndex, true);
                        break;
                    }
                    i++;
                }
            }
        }

        decoder.stop();
        decoder.release();

    }
}

这会产生下一个错误:(我无法发布图片:(,所以这里是链接)
Error_Log

我在带有VLC的笔记本电脑上测试了数据流并显示了视频,所以我想这部分是有用的 此外,该应用程序正在创建一个表面,它显示接收到一些数据。但是当它试图将输出缓冲区放到表面时,应用程序会退出错误。

我是解码的新手,这是我的第一个Android应用程序,所以我真的不知道要看。所以我希望有人能指出我正确的方向。

如果您有兴趣,我的整个代码都在此链接中:
H264_video.java

0 个答案:

没有答案