美文网首页
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