使用AVFoundation处理视频
使用AVAssetReader、AVAssetWriter编解码视频
之前的两篇文章浅略讲了iOS音视频开发相关代码实现;
在编码时关于音视频的相关参数比较多,这些参数不是随便什么数值就能行的;如果不理解缘由,而填写了不合适的参数,容易导致音视频处理过程中出现各种奇怪的问题;
只有明白了音视频相关的原理,才能理解各种参数的含义,才能更好的实现开发;
现在,就从音频入手,总结下音频相关的理论知识;
声音的本质
声音是如何产生的?
声音是由物体振动而产生的,一切正在发声的物体都在振动
当小球撞击到音叉的时候,音叉会发生振动,对周围的空气产生挤压,然后导致更大范围的空气跟着一起振动,最后我们耳朵旁边的空气也开始振动;这是因为空气产生了疏密变化,形成疏密相间的纵波,由此就产生了声波,声波一直延续到振动消失为止; 声波一直传入我们耳朵,就听到了声音;
我们说话时的声音,也是声带振动的结果;
声音的本质就是声波;
我们听到声音的过程:
声波 --> 耳廓(收集声波)--> 外耳道(传递声波) --> 鼓膜(将声波转换成振动) --> 听小骨(放大振动) --> 耳蜗(将振动转换成电信号) --> 听觉神经(传递电信号) --> 大脑(形成听觉)
声波的三要素
声波的三要素是频率、振幅和波形;频率代表音阶的高低,振幅代表响度,波形代表音色。
横坐标为时间,纵坐标为受振动的物体分子来回振动产生的位移;随着时间推移,分子的来回振动的轨迹,就是一个正弦或余弦函数的波形图;
频率
受振动的物体分子每秒来回振动的次数,叫做频率
;单位是秒分之一(1/s),也称为赫兹
(Hz);频率用来表示振动的快慢
(如441Hz代表每秒来回振动441次)
频率越高,波长就越短。反之频率越低波长则越长,低频率可以更容易地绕过障碍物,因此能量衰减就小,声音就会传得更远。
人类耳朵的听力有一个频率范围,大约是20Hz~20kHz,不过,即使是在这个频率范围内,不同的频率,听力的感觉也会不一样
振幅
物体未受到振动影响时的位置(横轴上)称为平衡位置;
从平衡位置到最大位移位置之间的距离,就叫做振幅
;
振幅代表响度,振幅越大表示响度越大能量越大,我们听到的声音就越大;
波形
上面我们说声波是正弦或余弦函数的图;但这是在单一频率的声波的情况下的;
事实上,声源的振动产生的并不是单一频率的声波,而是由基音和不同频率的泛音组成的复合声音;当声源的主体振动时会发出一个基音;同时其余各部分也有复合的声源,这些声源组合产生泛音(其实就是物理学上的谐波)
泛音决定了不同的音色
,不同的声源由于其材料、结构不同,泛音不同,则发出声音的音色也不同;
最后用一张图总结三要素
音频数字化
上面讲到声音的本质是声波的形式,声音属于模拟信号,但便于计算机处理和存储的是数字信号;所以需要将模拟信号(转成数字信号后进行存储。这一过程,即为音频数字化。
我们在互联网上听到的声音,都是先经过录制后转为了数字音频,再传输到互联网上的;
音频数字化的常见技术方案是脉冲编码调制(PCM,Pulse Code Modulation);
主要过程:采样 、量化 、编码。
采样
所谓采样就是 在时间轴上对信号进行数字化
模拟信号的波形是无限光滑的,可以看成由无数个点组成,由于存储空间是相对有限的,数字编码过程中,必须要对波形的点进行采样。采样就是每隔一段时间采集一次模拟信号的样本,在时间上将模拟信号离散化的过程。
根据采样定理(奈奎斯特–香农采样定理),只有当采样率高于声音信号最高频率的2倍时,才能把采集的声音信号唯一地还原成原来的声音;因此要按比声音最高频率高2倍以上的频率对声音进行采样;人耳能够听到的频率范围是20Hz~20kHz,所以采样频率一般为 44.1kHz,这样就可以保证采样声音达到20kHz也能被数字化,从而使得经过数字化处理之后,人耳听到的声音质量不会被降低。采样率
表示每秒采集的样本数量,44.1kHz就是代表1秒会采样44100次;
量化
量化是指在幅度轴上对信号进行数字化,将每一个采样点的样本值数字化
比如用16比特的二进制信号来表示声音的一个采样,而16比特所表示的 范围是[-32768,32767],共有2^16=625536个可能取值,因此最终模拟的音频信号在幅度上也分为了65536层
这里的16bit即为位深度
(采样精度/采样大小):使用多少个二进制位来存储一个采样点的样本值;位深度越高,表示的振幅越精确;
编码
所谓编码,就是按照一定的格式记录采样和量化后的数字数据,比如顺序存储或压缩存储,等等。
编码涉及了很多种格式,通常说的音频裸数据格式就是PCM(脉冲编码调制)数据。PCM需要以下几个概念:采样格式(sampleFormat)
、采样率 (sampleRate)
、声道数(channel)
。
采样格式:包含采样位深度、大小端模式、数据排列方式等;
以FFmpeg定义的sampleFormat为例:
enum AVSampleFormat {
AV_SAMPLE_FMT_NONE = -1,
AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
AV_SAMPLE_FMT_S16, ///< signed 16 bits
AV_SAMPLE_FMT_S32, ///< signed 32 bits
AV_SAMPLE_FMT_FLT, ///< float
AV_SAMPLE_FMT_DBL, ///< double
AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
AV_SAMPLE_FMT_FLTP, ///< float, planar
AV_SAMPLE_FMT_DBLP, ///< double, planar
AV_SAMPLE_FMT_S64, ///< signed 64 bits
AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar
AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};�����������������
其中U,S,F,D表示存储的类型,对应unsigned、signed、float和double类型;
数值表示位深度;
P表示声道数据排列方式为Planar
,还有排列方式为Packed
:
对于双声道音频来说,Packed表示两个声道的数据交错存储,交织在一起,即:
LRLRLRLR 的存储方式;
Planar 表示两个声道分开存储,也就是平铺分开,即:
LLLLRRRR 的存储方式;
以Packed存储方式为例 大端模式不同位深度数据存储如下:
声道:单声道产生一组声波数据,双声道(立体声)产生两组声波数据。
对于声音格式,还有一个概念用来描述它的大小,称为比特率(byteRate)
,即指单位时间内传输或处理的比特数量;单位是:比特每秒(bps),还有:千比特每秒(Kbps)、兆比特每秒(Mbps)等等;
以CD的音质为例:位深度为16比特(2字节),采样率为44.1kHZ,声道数为2,这些信息就描述了CD的音质。对于1分钟CD音质的数据,比特率为:
44100 * 16 * 2 = 1378.125 Kbps
存储空间为:
1378.125 * 60 / 8 / 1024 = 10.09MB
通常,采样率、位深度越高,数字化音频的质量就越好。从比特率的特性可以看得出来:比特率越高,数字化音频的质量也越好;我们所说的无损音乐,就是采样率、位深度都很高的,没有进行压缩处理的数字化声音;
最后还是用一张图总结数字化过程:
音频编解码
编码
前面计算了每分钟CD音质的数据采样格式,需要的存储空间约为10.1MB;在网络中传播的话,数据量太大了;
为了更便于存储和传输,一般都会使用某种音频编码对它进行编码压缩,然后再存成某种音频文件格式。
压缩分为无损压缩和有损压缩。
无损压缩:解压后可以完全还原出原始数据;
有损压缩:解压后不能完全还原出原始数据,会丢失一部分信息;一般是压缩掉冗余信号(冗余信号是指不能被人耳感知到的信号,包含人耳听觉范围之外的音频信号以及被掩蔽掉的音频信号等),不进行编码处理。
解码
当需要播放音频时,得先解码(解压缩)出PCM数据,然后再进行播放。
常见的编码格式:
WAV编码
WAV(Waveform Audio File Format),是由IBM和Microsoft开发的音频文件格式,扩展名是.wav,通常采用PCM编码,常用于Windows系统中;编码的一种实现就是在PCM数据格式的前面加上44字节,分别用来描述PCM的采样率、声道数、数据格式等信息。
- 特点:音质非常好,大量软件都支持。
- 适用场合:多媒体开发的中间文件、保存音乐和音效素材。
MP3编码
MP3(MPEG Audio Layer III)具有不错的压缩比,使用LAME编码的中高码率的MP3文件,听感上非常接近源WAV文件。
- 特点: 压缩比比较高,大量软件和硬件都支持,兼容性好。
- 适用场合:高比特率下对兼容性有要求的音乐欣赏。
AAC编码
AAC(Advanced Audio Coding)是新一代的音频有损压缩技术;
AAC编码的文件扩展名主要有3种:
- .acc:传统的AAC编码,使用MPEG-2 Audio Transport Stream(ADTS)容器
- .mp4:使用了MPEG-4 Part 14的简化版即3GPP Media Release 6 Basic(3gp6)进行封装的AAC编码
- .m4a:为了区别纯音频MP4文件和包含视频的MP4文件而由Apple公司使用的扩展名;
- 特点:在小于128Kbit/s的码率下表现优异,并且多用于视频中的音频编码。
- 适用场合:128Kbit/s以下的音频编码,多用于视频中音频轨的编码。
代码实现
- AVFoundation 音频编码
// -----解码----
// AVAssetReader
do {
reader = try AVAssetReader(asset: composition)
} catch let e {
callback(false, e)
return
}
reader.timeRange = CMTimeRange(start: .zero, duration: composition.duration)
// AVAssetReaderOutput
audioOutput = AVAssetReaderAudioMixOutput(audioTracks: audioTracks, audioSettings: nil)
audioOutput.alwaysCopiesSampleData = false
audioOutput.audioMix = audioMix
if reader.canAdd(audioOutput) {
reader.add(audioOutput)
}
if !reader.startReading() {
callback(false, reader.error)
return
}
// -----编码----
// AVAssetWriter
do {
writer = try AVAssetWriter(outputURL: outputUrl, fileType: .mp3)
} catch let e {
callback(false, e)
return
}
writer.shouldOptimizeForNetworkUse = true
let audioOutputSettings: [String : Any] = [
AVFormatIDKey: NSNumber(value: kAudioFormatMPEGLayer3),
AVNumberOfChannelsKey: NSNumber(value: 2),
AVSampleRateKey: NSNumber(value: 44100),
AVEncoderBitRateKey: NSNumber(value: 128000)
]
// AVAssetWriterInput
audioInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioOutputSettings)
if writer.canAdd(audioInput) {
writer.add(audioInput)
}
writer.startWriting()
writer.startSession(atSourceTime: .zero)
// 准备写入数据
videoInput.requestMediaDataWhenReady(on: inputQueue) { [weak self] in
...
}
其中audioOutputSettings的4项就对应上面分析过的: 编码格式,声道数,采样率,比特率;这些设置最终决定了编码后音频的格式、音频的存储空间及音质;
而且这些设置都是固定组合的,不同编码格式Format所需的Key有所不一样;
wav/pcm 格式设置(需要pcm相关设置):
let audioOutputSettings: [String : Any] = [
AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),
AVNumberOfChannelsKey: NSNumber(value: 2),
AVSampleRateKey: NSNumber(value: 44100),
AVLinearPCMBitDepthKey: NSNumber(value: 16),
AVLinearPCMIsBigEndianKey: NSNumber(value: false),
AVLinearPCMIsFloatKey: NSNumber(value: false),
AVLinearPCMIsNonInterleaved: NSNumber(value: false)
]
- FFmpeg
// 解码 mp3-->pcm
ffmpeg -i test.mp3 -acodec pcm_s16le -f s16le -ac 2 -ar 44100 test.pcm
// 编码 pcm-->mp3
ffmpeg -f s16le -ac 2 -ar 44100 -acodec pcm_s16le -i test test_new.mp3
播放pcm
ffplay -i crop.pcm -ar 44100 -ac 2 -f s16le
续篇:
音视频开发基础理论-视频篇