美文网首页
Android 硬件编码 MediaCodec

Android 硬件编码 MediaCodec

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

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

    初始化

    configure 编码器的时候要将flag 设置为encode。

    public void startEncode(MediaFormat format) {
        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.createEncoderByType(mimeType);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        mCodec.configure(format,null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mCodec.start();
    }
    

    写数据

    将原始数据送给 MediaCodec。

    public void sendFrame(byte[] input, long pts, int flags) {
        int size = input.length;
        int inputBufferId = mCodec.dequeueInputBuffer(timeOut);
        if (inputBufferId >= 0) {
            // fill inputBuffers[inputBufferId] with valid data
            ByteBuffer buffer = mCodec.getInputBuffer(inputBufferId);
            buffer.put(input);
            mCodec.queueInputBuffer(inputBufferId, 0, size, pts, flags);
        }
    }
    

    取数据

    从 MediaCodec 中取出编码后的数据,这里要注意返回的outputBufferId,会有不同的处理。

    public VEAVPacket receivePacket() {
        VEAVPacket packet = new VEAVPacket();
        int outputBufferId = mCodec.dequeueOutputBuffer(mBufferInfo, timeOut);
        if (outputBufferId == MediaCodec.INFO_TRY_AGAIN_LATER) {
            Log.d(TAG, "INFO_TRY_AGAIN_LATER");
            return packet;
        } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            // Subsequent data will conform to new format.
            packet.format = mCodec.getOutputFormat();
            return packet;
        } else if (outputBufferId < 0) {
            Log.d(TAG, "receivePacket:" + outputBufferId);
            return packet;
        }
        // outputBuffers[outputBufferId] is ready to be processed or rendered.
        ByteBuffer outputBuffer = mCodec.getOutputBuffer(outputBufferId);
        if (outputBuffer == null) {
            return packet;
        }
        byte[] outData = new byte[mBufferInfo.size];
        outputBuffer.get(outData);
        packet.buffer = ByteBuffer.wrap(outData);
        packet.bufferInfo = mBufferInfo;
        mCodec.releaseOutputBuffer(outputBufferId, timeOut);
    
        return packet;
    }
    

    结束

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

    注意事项

    封装的时候可能提前需要获取 sps 和 pps,然而编码器接收到一定数据才会吐出这些信息,因此,我们可以先送入一些空数据,将这个信息给挤出来。

    public MediaFormat getOutputFormat() {
        if (mOutFormat != null) {
            return mOutFormat;
        }
        byte [] data = new byte[1];
    
        long time = System.currentTimeMillis();
        sendFrame(data, time, 0);
    
        VEAVPacket videoPacket = receivePacket();
        if (videoPacket.format != null) {
            mOutFormat = videoPacket.format;
        }
        return mOutFormat;
    }
    

    相关文章

      网友评论

          本文标题:Android 硬件编码 MediaCodec

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