MediaCodec 初探

    最近分析了一个关于MediaCodec的花屏问题,记录一下文档以备后面使用。

    MediaCodec这个类是Android4.1开始引入的,API16。这个类可以在设备上直接访问媒体的解码,一般称为硬解码。

    在Android4.3之后,API18MediaCodec扩展了一个方法createInputSurface,提供了一个通过Surface作为输入。这样允许输入来自于摄像头的预览或者OpenGL ES渲染。

    在Android5.0之后,API21,开启了异步模式,它提供了一个回调方法,当缓冲器允许的时候才开始执行。

 

基本的用法:

我们先使用同步模式开始,异步模式单独介绍。只有三步

 

  1. 创建和配置MediaCodec对象
  2. 一个循环 循环内容如下
  3. 释放MediaCodec对象
  • 判断输入缓冲是否准备好,如果准备好,读一块输入到缓存中
  • 判断输出缓冲是否准备好,如果准备好,拷贝缓存内容到输出

1、创建和配置MediaCodec对象

    //配置格式,长度,宽度等参数
    MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, width, height);
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
    format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
    format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);

    //解码器的创建和配置
    MediaCodec mEncoder;
    mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
    mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

    //输入的数据来源   
    Surface mInputSurface = mEncoder.createInputSurface();

    //解码开始
    mEncoder.start();

3、释放对象,为了记住这一点,可以先写好,后面再写循环体

        //配置需要释放么?不需要,自己再想想

        //解码器,需要停下来,然后释放
        if (mEncoder != null) {
            mEncoder.stop();
            mEncoder.release();
            mEncoder = null;
        }

2、中间的解码和循环

//解码所需的缓存
MediaCodec.BufferInfo mBufferInfo;
ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();


//循环一直讲视频播放完毕
while (true) {
        //解码
        int encoderStatus = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
        ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];

        //这个地方忽略异常处理,调整位置
        if (mBufferInfo.size != 0) {
            encodedData.position(mBufferInfo.offset);
            encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
        }

        //将解码好的数据扔到窗体上
        mEncoder.releaseOutputBuffer(encoderStatus, false);

        //确认是文件结束,退出循环
        if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
            break;
        }
}

什么?MediaCodec的硬解码就这么简单,对,就这么简单,这就是核心技术,O(∩_∩)O哈哈~

我们看看谷歌官方的代码,复习一下,拾遗补漏

第一步

MediaCodec codec = MediaCodec.createByCodecName(name);
codec.configure(format, …);
MediaFormat outputFormat = codec.getOutputFormat(); // option B
codec.start();

第三步,呵呵

codec.stop();
codec.release()

第二步:

//一样是个循环,中文注释是我加的,英语都是谷歌的
for (;;) {

    //解码帧
    int inputBufferId = codec.dequeueInputBuffer(timeoutUs);
    if (inputBufferId >= 0) {
      ByteBuffer inputBuffer = codec.getInputBuffer(…);
      // fill inputBuffer with valid data
      …
      codec.queueInputBuffer(inputBufferId, …);
    }

    //输出缓存
    int outputBufferId = codec.dequeueOutputBuffer(…);
    if (outputBufferId >= 0) {
      ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
      MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
      // bufferFormat is identical to outputFormat
      // outputBuffer is ready to be processed or rendered.
      …
      //将缓存送到输出的位置
      codec.releaseOutputBuffer(outputBufferId, …);
    } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
      //解码换格式了,太无耻了,不能解码输出干了一半,还换格式。
      //这个应该是在解码之前发生一次,如果解码一半还换格式,就不干了,抛异常
      // Subsequent data will conform to new format.
      // Can ignore if using getOutputFormat(outputBufferId)
      outputFormat = codec.getOutputFormat(); // option B
    }
  }

官方即使是同步模式,还有两种处理方式,而且不能混用哦!

1、使用缓存的同步处理方式(Synchronous Processing using Buffers)

2、使用缓存数组的同步处理方式(Synchronous Processing using Buffer Arrays)

就到这来吧,今天先写到这里

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值