音视频开发系列(31)MediaCodec硬编解流程与实践

本文深入探讨Android MediaCodec的工作原理、生命周期、数据格式、同步异步模式,并通过 AAC 解码到 PCM 的同步和异步实现,详细解析音视频编解码流程,同时分享实践中遇到的问题和解决策略。
摘要由CSDN通过智能技术生成

一、介绍

Android底层多媒体模块采用的是OpenMax框架,实现方都要遵循OpenMax标准。Google默认提供了一系列的软编软解的实现,而硬编硬解则由芯片厂商完成,所以不同芯片的手机,硬编硬解的实现和性能是会有差异的。比如我手机的编解码实现部分如下

MediaCodec提供了一套访问底层多媒体模块的接口供应用层实现编解码功能。

二、工作原理和基本流程

MediaCodec使用的基本流程如下:

- createByCodeName/createEncoderByType/createDecoderByType: (静态工厂构造MediaCodec对象)--Uninitialized状态
- configure:(配置) -- configure状态
- start        (启动)--进入Running状态
- while(1) {
    try{
       - dequeueInputBuffer    (从编解码器获取输入缓冲区buffer)
       - queueInputBuffer      (buffer被生成方client填满之后提交给编解码器)
       - dequeueOutputBuffer   (从编解码器获取输出缓冲区buffer)
       - releaseOutputBuffer   (消费方client消费之后释放给编解器)
    } catch(Error e){
       - error                   (出现异常 进入error状态)
    }
    
}
- stop                          (编解码完成后,释放codec)
- release

基本流程结合代码两张Buffer队列示意图和生命周期图一起看,整个流程就会很清晰。

下面我们重点看下核心的部分Buffer队列的操作。
MediaCodec采用了2个缓冲区队列(inputBuffer和outputBuffer),异步处理数据,

1. 数据生成方(左侧Client)从input缓冲队列申请empty buffer—》dequeueinputBuffer
2. 数据生产方(左侧Client)把需要编解码的数据copy到empty buffer,然后繁缛到input缓冲队列 —》queueInputBuffer
3. MediaCodec从input缓冲区队列中取一帧进行编解码处理
4. 编解码处理结束后,MediaCodec将原始inputbuffer置为empty后放回左侧的input缓冲队列,将编解码后的数据放入到右侧output缓冲区队列
5. 消费方Client(右侧Client)从output缓冲区队列申请编解码后的buffer —》dequeueOutputBuffer
6. 消费方client(右侧Client)对编解码后的buffer进行渲染或者播放
7. 渲染/播放完成后,消费方Client再将该buffer放回到output缓冲区队列 —》releaseOutputBuffer

三、数据格式

Mediacodec接受三种数据格式和两种载体 分别如下:
压缩数据、原始音频数据和原始视频数据
以Surface作为载体或者ByteBuffer作为载体

  1. 压缩数据
    压缩数据可以作为解码器的输入、编码器的输出,需要指定数据的格式,这样codec才知道如何处理这些压缩数据

  2. 原始音频数据 — PCM音频数据帧

  3. 原始视频数据
    视频看解码支持的常用的色彩格式有 native raw video format和 flexible YUV buffers
    native raw video format : COLOR_FormatSurface,可以用来处理surface模式的数据输入输出。
    flexible YUV buffers : 例如COLOR_FormatYUV420Flexible,可以用来处理surface模式的输出输出,在使用ByteBuffer模式的时候可以用getInput/OutputImage(int)方法来获取image数据。

四、生命周期

MediaCodec生命周期状态分为三种 Stopped、Executing和Released
在上面第一部分工作原理和基本流程中我们也简单提到了,下面我们详细说下
其中Stopped包含三种子状态 Uninitialized(为初始化状态)、Configured(已配置状态)、Error(异常状态)
Executing也包含三个子状态 Flushed(刷新状态)、Running(运行状态)和EOS(流结束状态)
我们重点看下Executing状态
在调用mediacodec.start()方法后编解码器立即进入Executing状态的Flush子状态,此时编解码器会拥有所有的inputBuffer
一旦第一个输入缓存inputbuffer被移出队列(即:queueInputBuffer),编解码器转为Running状态,编解码器的大部分生命周期会在此状态下。
当带有end-of-stream标记的inputBuffer入队列时(queueInputBuffer),编解码器将转入EOS状态。在这种状态下,编解码器不再接收新的inputBuffer,但是仍然产生outputBuffer,直到end-of-stream标记到达输出端。
可以在Executiong下的任何时候调用flush()使编解码器重新回到Flushed状态。

关注+后台私信我,领取2022最新最全学习提升资料+面试题,内容包括(

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值