[FFMpeg] android中极端码率和帧率

172 阅读1分钟

心血来潮,编码时想自己计算一下码率和帧率

核心点:

  • 利用现有的固定帧率mFrameRate,计算两个buffer时间间隔内 elapsedUs,处理了多少帧 tempFrameCount,然后除以elapsedUs,得到一个动态的帧率
  • 将当前视频帧 乘以8 ,换算为比特数,然后除以时间间隔:elapsedUs
public void encodeFrame(byte[] input) {
    if (mEncoder == null) {
        return;
    }
    int inputBufferIndex = mEncoder.dequeueInputBuffer(-1);
    if (inputBufferIndex >= 0) {
        ByteBuffer inputBuffer = mEncoder.getInputBuffer(inputBufferIndex);
        inputBuffer.clear();
        inputBuffer.put(input);
        mEncoder.queueInputBuffer(inputBufferIndex, 0, input.length, mPresentationTimeUs, 0);
        mPresentationTimeUs += 1000000L / mFrameRate;

        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();

        int outputBufferIndex = mEncoder.dequeueOutputBuffer(bufferInfo, 0);
        while (outputBufferIndex >= 0) {
            ByteBuffer outputBuffer = mEncoder.getOutputBuffer(outputBufferIndex);
            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                bufferInfo.size = 0;
            }
            if (bufferInfo.size != 0) {
                if (!mMuxerStarted) {
                    throw new RuntimeException("muxer hasn't started");
                }
                // pts: 当前buffer的pts : 微秒
                long presentationTimeUs = bufferInfo.presentationTimeUs;
                // 经过的时间
                long elapsedUs          = presentationTimeUs - mPresentationTimeUs;
                if (elapsedUs >= 1000000L) {
                    // 它将当前帧的大小 bufferInfo.size 与前一帧的大小 mPrevOutputSize 相加,得到当前帧的总大小
                    long outputSize = bufferInfo.size + mPrevOutputSize;
                    // 帧率:它首先计算两个时间戳之间的时间差 elapsedUs,单位是微秒。
                    // 然后,它使用当前帧率 mFrameRate 和时间差 elapsedUs 计算出当前帧的帧率 frameRate
                    int frameRate = (int) (1000000L * mFrameRate * (elapsedUs / 1000000L)) / (int) elapsedUs;
                    // 比特率:它首先将视频帧的大小 outputSize 转换为比特数,然后使用时间差 elapsedUs 计算出比特率。
                    // 具体来说,它将视频帧的比特数乘以 1000000L,
                    // 然后除以时间差 elapsedUs。由于视频帧的大小是以字节为单位的,因此需要将结果乘以 8,以将比特率转换为比特每秒(bps)
                    int bitrate = (int) (8 * outputSize * 1000000L / elapsedUs);
                    Log.d("VideoEncoder", "Frame rate: " + frameRate + ", Bitrate: " + bitrate);
                    mPrevPresentationTimeUs = presentationTimeUs;
                    mPrevOutputSize = 0;

                }
                mPrevOutputSize += bufferInfo.size;
            }
            mEncoder.releaseOutputBuffer(outputBufferIndex, false);
            outputBufferIndex = mEncoder.dequeueOutputBuffer(bufferInfo, 0);
        }


    }
}