美文网首页
Android 硬件解码 MediaCodec

Android 硬件解码 MediaCodec

作者: zhonglaoban | 来源:发表于2023-10-25 19:06 被阅读0次
    MediaCodec.jpg

    MediaCodec 的整体流程如上图所示,从input 输入数据,从output 输出数据。解码的时候输入的是压缩数据,输出的是解码后的原始数据。

    初始化

    如果传入了 Surface,那么解码完的数据可以直接渲染到 Surface 上。

    public void startDecode(MediaFormat format, SurfaceView surfaceView) {
        Surface surface = surfaceView.getHolder().getSurface();
        mFormat = format;
        final String mimeType = format.getString(MediaFormat.KEY_MIME);
    
        // Check to see if this is actually a video mime type. If it is, then create
        // a codec that can decode this mime type.
        try {
            mCodec = MediaCodec.createDecoderByType(mimeType);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        mCodec.configure(format,surface, null, 0);
        mCodec.start();
    }
    

    写数据

    将压缩的数据送入解码器。

    public void sendPackage(VEAVPacket packet) {
        int size = packet.buffer.capacity();
        int inputBufferId = mCodec.dequeueInputBuffer(timeOut);
        if (inputBufferId >= 0) {
            // fill inputBuffers[inputBufferId] with valid data
            ByteBuffer buffer = mCodec.getInputBuffer(inputBufferId);
            buffer.put(packet.buffer);
            mCodec.queueInputBuffer(inputBufferId, 0, size, packet.dts, packet.flag);
        }
    }
    

    取数据

    如果不直接渲染到 Surface 上,我们也可以把解压后的数据取出来。

    public VEAVFrame receiveFrame() {
        VEAVFrame frame = new VEAVFrame();
        int outputBufferId = mCodec.dequeueOutputBuffer(mBufferInfo, timeOut);
        if (outputBufferId == MediaCodec.INFO_TRY_AGAIN_LATER) {
            Log.d(TAG, "INFO_TRY_AGAIN_LATER");
            return frame;
        }  else if (outputBufferId < 0) {
            Log.d(TAG, "receiveFrame:" + outputBufferId);
            return frame;
        }
        // outputBuffers[outputBufferId] is ready to be processed or rendered.
        ByteBuffer outputBuffer = mCodec.getOutputBuffer(outputBufferId);
        if (outputBuffer == null) {
            return frame;
        }
        byte[] outData = new byte[mBufferInfo.size];
        outputBuffer.get(outData);
        frame.data = outData;
        mCodec.releaseOutputBuffer(outputBufferId, timeOut);
    
        return frame;
    }
    

    直接渲染到 Surface 上

    releaseOutputBuffer 里面的 boolean 变量控制这一帧是否需要渲染。

    public void renderToSurface() {
        int outputBufferId = mCodec.dequeueOutputBuffer(mBufferInfo, timeOut);
        if (outputBufferId < 0) {
            return;
        }
        mCodec.releaseOutputBuffer(outputBufferId, true);
    }
    

    结束

    public void stopDecode() {
        mCodec.stop();
        mCodec.release();
    }
    

    注意事项

    renderToSurface 的频率需要外部控制,不然会一下子全部渲染完了。

    相关文章

      网友评论

          本文标题:Android 硬件解码 MediaCodec

          本文链接:https://www.haomeiwen.com/subject/rtoeidtx.html