Android-NDK-011-Android⾳频基础理论

62 阅读10分钟

学术概念

采样和采样频率:

⼀秒钟内采样的次数称为采样频率。采样频率越⾼,越接近原始信号,但是也加⼤了运算处理的复杂度。根据 Nyquist采样定理,要想重建原始信号,采样频率必须⼤于信号中最⾼频率的两倍。⼈能感受到的频率范围为 20HZ--20kHZ, ⼀般⾳乐的采样频率为44.1kHZ, 更⾼的可以是48kHZ和96kHZ,不过⼀般⼈⽤⽿听感觉不出差别 了。语⾳主要是以沟通为主,不需要像⾳乐那样清晰,⽤16k采样的语⾳就称为⾼清语⾳了。现在主流的语⾳采样 频率为16kHz。

采样位数

数字信号是⽤0和1来表示的。采样位数就是采样值⽤多少位0和1来表示,也叫采样精度,⽤的位数越多就越接近 真实声⾳。如⽤8位表示,采样值取值范围就是-128--127,如⽤16位表示,采样值取值范围就是-32768--32767。 现在⼀般都⽤16位采样位数。

声道:

声道是指处理的声⾳是单声道还是⽴体声。Android⽀持双声道⽴体声和单声道。CHANNEL_IN_MONO单声道, CHANNEL_IN_STEREO⽴体声。单声道在声⾳处理过程中只有单数据流,⽽⽴体声则需要左、右声道的两个数据 流。显然,⽴体声的效果要好,但相应的数据量要⽐单声道的数据量加倍。

码率:

就是⽐特率。⽐特率是指每秒传送的⽐特(bit)数。

⾳频采集和播放:

⼀般⽤专⻔的芯⽚(通常叫codec芯⽚)采集⾳频,做AD转换,然后把数字信号通过I2S总线(主流⽤I2S总线, 也可以⽤其他总线,⽐如PCM总线)送给CPU处理(也有的会把codec芯⽚与CPU芯⽚集成在⼀块芯⽚中)。当要 播放时CPU会把⾳频数字信号通过I2S总线送给codec芯⽚,然后做DA转换得到模拟信号再播放出来。

⾳频编码过程

傅⽴叶变

参考资料如下: www.bilibili.com/video/BV1kX…

Android⾳频架构

应⽤框架

应⽤框架包含应⽤代码,该代码使⽤ android.media API 与⾳频硬件进⾏交互。在内部,此代码会调⽤相应的 JNI 粘合类来访问与⾳频硬件互动的原⽣代码。

JNI

与 android.media 关联的 JNI 代码会调⽤较低级别的原⽣代码来访问⾳频硬件。JNI 位于 frameworks/base/core/jni/ 和 frameworks/base/media/jni 中。

原⽣框架

原⽣框架提供相当于 android.media 软件包的原⽣软件包,它调⽤ Binder IPC 代理来访问媒体服务器的⾳频专属 服务。 原⽣框架代码位于 frameworks/av/media/libmedia 中。

Binder IPC

Binder IPC 代理⽤于促进跨越进程边界的通信。代理位于 frameworks/av/media/libmedia 中,并以字⺟“I”开 头。

媒体服务器

媒体服务器包含⾳频服务,这些⾳频服务是与您的 HAL 实现进⾏交互的实际代码。媒体服务器位于 frameworks/av/services/audioflinger 中。

HAL

HAL 定义了⾳频服务会调⽤且您必须实现才能使⾳频硬件正常运⾏的标准接⼝

FFmpeg了解Audio

image.png

Auido的内容主要取决编码的协议。

OpenSL ES

developer.android.google.cn/ndk/guides/…

OpenSL ES全称为Open Sound Library for Embedded Systems,即嵌⼊式⾳频加速标准。OpenSL ES是⽆授权 费、跨平台、针对嵌⼊式系统精⼼优化的硬件⾳频加速 API。它为嵌⼊式移动多媒体设备上的本地 应⽤程序开发者 提供了标准化、⾼性能、低响应时间的⾳频功能实现⽅法,同时还实现了软/硬件⾳频性能的直接跨平台部署,不 仅降低了执⾏难度,⽽且促进了⾼级⾳频市场的发展。简单来说OpenSL ES是⼀个嵌⼊式跨平台免费的⾳频处理 库。 所以它不是Android特有的。

OpenSL ES的特性以及优劣势。

特性:

(1)C 语⾔接⼝,兼容 C++,需要在 NDK 下开发,能更好地集成在 native 应⽤中

(2)运⾏于 native 层,需要⾃⼰管理资源的申请与释放,没有 Dalvik 虚拟机的垃圾回收机制

(3)⽀持 PCM 数据的采集,⽀持的配置:16bit 位宽,16000 Hz采样率,单通道。(其他的配置不能保证兼容所 有平台)

(4)⽀持 PCM 数据的播放,⽀持的配置:8bit/16bit 位宽,单通道/双通道,⼩端模式,采样率(8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 Hz)

(5)⽀持播放的⾳频数据来源:res ⽂件夹下的⾳频、assets ⽂件夹下的⾳频、sdcard ⽬录下的⾳频、在线⽹络 ⾳频、代码中定义的⾳频⼆进制数据等等

缺点:

(1)不⽀持版本低于 Android 2.3 (API 9) 的设备

(2)没有全部实现 OpenSL ES 定义的特性和功能

(3)不⽀持 MIDI

(4)不⽀持直接播放 DRM 或者 加密的内容

(5)不⽀持⾳频数据的编解码,如需编解码,需要使⽤ MediaCodec API 或者第三⽅库

(6)在⾳频延时⽅⾯,相⽐于上层 API,并没有特别明显地改

OpenSLES重要概念

Objects和Interfaces

在OpenSL ES的开发中有两个必须理解的概念,⼀个是Object,另⼀个是Interface。因为很多的API都是在操作 Object和Interface。Android为了更⽅便的使⽤OpenSL ES把OpenSL ES 的API设计成了类似⾯向对象的java的使 ⽤⽅式了。Object 可以想象成 Java 的 Object 类,Interface 可以想象成 Java 的 Interface,但它们并不完全相 同。

他们的关系:

(1) 每个 Object 可能会存在⼀个或者多个 Interface,官⽅为每⼀种 Object 都定义了⼀系列的 Interface

(2)每个 Object 对象都提供了⼀些最基础的操作,⽐如:Realize,Resume,GetState,Destroy 等等,如果希 望使⽤该对象⽀持的功能函数,则必须通过其 GetInterface 函数拿到 Interface 接⼝,然后通过 Interface 来访问 功能函数

(3)并不是每个系统上都实现了 OpenSL ES 为 Object 定义的所有 Interface,所以在获取 Interface 的时候需要 做⼀些选择和判断

所有的Object在OpenSL⾥⾯我们拿到的都是⼀个SLObjectItf

typedef const struct SLObjectItf_ * const * SLObjectItf;
struct SLObjectItf_ {
    SLresult (*Realize) (
        SLObjectItf self,
        SLboolean async
    );
    SLresult (*Resume) (
        SLObjectItf self,
        SLboolean async
    );
    SLresult (*GetState) (
        SLObjectItf self,
        SLuint32 * pState
    );
    SLresult (*GetInterface) (
        SLObjectItf self,
        const SLInterfaceID iid,
        void * pInterface
    );
    SLresult (*RegisterCallback) (
        SLObjectItf self,
        slObjectCallback callback,
        void * pContext
    );
    void (*AbortAsyncOperation) (
        SLObjectItf self
    );
    void (*Destroy) (
        SLObjectItf self
    );
    SLresult (*SetPriority) (
        SLObjectItf self,
        SLint32 priority,
        SLboolean preemptable
    );
    SLresult (*GetPriority) (
        SLObjectItf self,
        SLint32 *pPriority,
        SLboolean *pPreemptable
    );
    SLresult (*SetLossOfControlInterfaces) (
        SLObjectItf self,
        SLint16 numInterfaces,
        SLInterfaceID * pInterfaceIDs,
        SLboolean enabled
    );
};

GetInterface

GetInterface可以说是OpenSL⾥使⽤频率最⾼的⽅法,通过它我们可以获取Object⾥⾯的Interface。

由于⼀个Object⾥⾯可能包含了多个Interface,所以GetInterface⽅法有个SLInterfaceID参数来指定到的需要获取 Object⾥⾯的那个Interface。

⽐如我们通过EngineObject去获取SL_IID_ENGINE这个id的Interface,⽽这个id对应的Interface就是SLEngineItf:

SLresult (*CreateAudioPlayer) (
    SLEngineItf self,
    SLObjectItf * pPlayer,
    SLDataSource *pAudioSrc,
    SLDataSink *pAudioSnk,
    SLuint32 numInterfaces,
    const SLInterfaceID * pInterfaceIds,
    const SLboolean * pInterfaceRequired
);
SLresult (*CreateAudioRecorder) (
    SLEngineItf self,
    SLObjectItf * pRecorder,
    SLDataSource *pAudioSrc,
    SLDataSink *pAudioSnk,
    SLuint32 numInterfaces,
    const SLInterfaceID * pInterfaceIds,
    const SLboolean * pInterfaceRequired
);
// 还有很多其它的,可以看下OpenSLES.h的头⽂件

Object的⽣命周期

OpenSL ES 的 Object ⼀般有三种状态,分别是:UNREALIZED (不可⽤),REALIZED(可⽤),SUSPENDED (挂起)。

Object 处于 UNREALIZED (不可⽤)状态时,系统不会为其分配资源;调⽤ Realize ⽅法后便进⼊ REALIZED (可⽤)状态,此时对象的各个功能和资源可以正常访问;当系统⾳频相关的硬件设备被其他进程占⽤时, OpenSL ES Object 便会进⼊ SUSPENDED (挂起)状态,随后调⽤ Resume ⽅法可使对象重回 REALIZED(可 ⽤)状态;当 Object 使⽤结束后,调⽤ Destroy ⽅法释放资源,是对象重回 UNREALIZED (不可⽤)状态。

实战1

⾳频录制、播放 ⾼层API和底层的API的结合,重点掌握OpenSL ES播放的流程。

编码的基础概念

对于视频数据⽽⾔,视频编码的最主要⽬的是数据压缩。这是因为动态图像的像素形式表示数据量极为巨⼤,存储 空间和传输带宽完全⽆法满⾜保存和传输的需求。例如,图像的每个像素的三个颜⾊分量RGB各需要⼀个字节表 示,那么每⼀个像素⾄少需要3字节,分辨率1280×720的图像的⼤⼩为2.76M字节。

  • 时间冗余:视频相邻的两帧之间内容相似,存在运动关系
  • 空间冗余:视频的某⼀帧内部的相邻像素存在相似性
  • 编码冗余:视频中不同数据出现的概率不同 视觉冗余:观众的视觉系统对视频中不同的部分敏感度不同

视频编码标准化组织

从事视频编码算法的标准化组织主要有两个,ITU-T和ISO。 ITU-T,全称International Telecommunications Union - Telecommunication Standardization Sector,即国际 电信联盟——电信标准分局。该组织下设的VECG(Video Coding Experts Group)主要负责⾯向实时通信领域的标 准制定,主要制定了H.261/H263/H263+/H263++等标准。 ISO,全称International Standards Organization,即国际标准化组织。该组织下属的MPEG(Motion Picture Experts Group),即移动图像专家组主要负责⾯向视频存储、⼴播电视、⽹络传输的视频标准,主要制定了 MPEG-1/MPEG-4等。

为什么要编码?

视频是由⼀帧帧的图⽚组成. 以⼀个时⻓ 1⼩时,帧率为30fps, 分辨率为1080P的视频举例, ⼀帧未压缩的图⽚ (yuv420)⼤⼩为:

1920∗1080+1920∗1080/4+1920∗1080/4=3110400 byte

视频总⼤⼩为 3110400 ∗ 30 ∗ 3600 = 335923200000 byte ≈ 313 G

帧间压缩和帧内压缩

时间冗余

视频⼀般由时间轴区间内⼀组连续画⾯组成,其中的相邻帧往往包含相同的背景和移动物体,只不过移动物体所在 的空间位置略有不同,所以后⼀帧的数据与前⼀帧的数据有许多共同的地⽅,这就称为时间冗余。

空间冗余

我们常⻅到的jpeg图⽚, 就是⼀种对静态数据的压缩,可以理解为视频的帧内压缩. ⼀幅图像相邻像素间往往存 在着空间连贯性.

image.png

IBPframe

在⾳视频中,为了提⾼压缩效率,会将每帧画⾯压缩为不同类型的视频帧数据。

  • I帧表示关键帧,包含有⼀帧画⾯的完整信息,解码时只需要本帧数据就可以解码出完整的⼀帧画⾯。
  • P帧表示前向参考帧,它保存了本帧与上⼀帧的差异信息,它不能单独解码,需要根据上⼀帧的画⾯加上本帧保存的差值来获取本帧的完整画⾯。
  • B帧为双向参考帧,它解码时需要依赖它之前和之后的帧来获取最终的画⾯。因为B帧需要依赖它后⾯的帧来进⾏解码,所以它的解码顺序就必然和显示顺序不能保持⼀致,这时就需要解码时间戳(DTS)和显示时间戳(PTS)来共同决定⼀帧视频数据何时解码,然后何时显示了。

audio物理量

声⾳是⼀种空⽓振动产⽣的波。

  • 频率(Frequency) 单位时间内,声波的周期数,Hz表示
  • 振幅(Amplitude ) 波振动的⼤⼩,⼀般⽤dB表示
  1. ⾳调(Pitch):声⾳频率的⾼低⾳调主要由声⾳的频率决定,同时也与声⾳ 强度有关。
  2. ⾳量(响度): 是指⼈⽿对所听到的声⾳⼤⼩强弱的主观感受。
  3. ⾳⾊(⾳品): 每个⼈的声⾳以及各种乐器所发出的声⾳ 的区别,就是由⾳⾊不同造成的。

Audition专业软件基本认知

实战教学

Android 官方: developer.android.com/ndk/guides/…