最近在玩一个类似小咖秀的项目,所以对AVFoundation有了一些的研究。这是AVFoundation的第一篇,准备先介绍一些AVFoundation中的基础知识
音频采样
大自然中的声音,他的形态是一种波。我们通过采样,将这种波量化成数据,记录下来,如下图所示:
如上图所示,采样的数据并不能完整的还原出原来的波形,只能做到尽量接近原波形。并且采样率(采样的次数)越高,波形越接近原波形。不过采样的次数增多,必然会导致存储的数据量要增加,所以我们不可能无限提升采样率。经过长期的研究人们发现,当采样率等于波形中最高频率的2倍时,已经足够将波形还原到可接受的程度了。这个频率称为奈奎斯特频率。人耳能接受的最高频率为20kHz,所以只要采样率超过40kHz,就可以呈现出可接受的声音。目前常见的CD采样率为44.1kHz。
除了采样率之外,音频采样还有一个重要参数叫做音频的位元深度。表示用多少位(bit)定义线性维度上的离散度来保存一个音频样本。位数越高,离散度越多,表示的声音越精确(音质越好)。一般来说16bit比较常见,可以表示65536个离散度。
一个音频文件的体积,有如下算法:体积=采样率*位元深度*音道数*时间
。
音频压缩
对声音进行采样、量化过程被称为脉冲编码调制(Pulse Code Modulation),直接脉冲编码调制(Linear Pulse Code Modulation)产生的数据称为Linear PCM数据,LPCM数据是最原始的音频数据完全无损,但是他的体积非常大,比如一个44.1kHz,16bit,双音道的音频文件,每分钟的数据量为44.1*16*2*60kbit=10.3M。一个普通5分钟的音乐就得50M,这个数据量对普通用户来说是过于庞大的。
为了解决这个问题,诞生了一系列的压缩算法,其中主要分为有无损压缩(ALAC、APE、FLAC)和有损压缩(MP3、AAC、OGG、WMA)两种。其具体的压缩算法对应到AVFoundation的CoreAudioTypes.h
中有:
CF_ENUM(AudioFormatID)
{
kAudioFormatLinearPCM = 'lpcm',
kAudioFormatAC3 = 'ac-3',
kAudioFormat60958AC3 = 'cac3',
kAudioFormatAppleIMA4 = 'ima4',
kAudioFormatMPEG4AAC = 'aac ',
kAudioFormatMPEG4CELP = 'celp',
kAudioFormatMPEG4HVXC = 'hvxc',
kAudioFormatMPEG4TwinVQ = 'twvq',
kAudioFormatMACE3 = 'MAC3',
kAudioFormatMACE6 = 'MAC6',
kAudioFormatULaw = 'ulaw',
kAudioFormatALaw = 'alaw',
kAudioFormatQDesign = 'QDMC',
kAudioFormatQDesign2 = 'QDM2',
kAudioFormatQUALCOMM = 'Qclp',
kAudioFormatMPEGLayer1 = '.mp1',
kAudioFormatMPEGLayer2 = '.mp2',
kAudioFormatMPEGLayer3 = '.mp3',
kAudioFormatTimeCode = 'time',
kAudioFormatMIDIStream = 'midi',
kAudioFormatParameterValueStream = 'apvs',
kAudioFormatAppleLossless = 'alac',
kAudioFormatMPEG4AAC_HE = 'aach',
kAudioFormatMPEG4AAC_LD = 'aacl',
kAudioFormatMPEG4AAC_ELD = 'aace',
kAudioFormatMPEG4AAC_ELD_SBR = 'aacf',
kAudioFormatMPEG4AAC_ELD_V2 = 'aacg',
kAudioFormatMPEG4AAC_HE_V2 = 'aacp',
kAudioFormatMPEG4AAC_Spatial = 'aacs',
kAudioFormatAMR = 'samr',
kAudioFormatAMR_WB = 'sawb',
kAudioFormatAudible = 'AUDB',
kAudioFormatiLBC = 'ilbc',
kAudioFormatDVIIntelIMA = 0x6D730011,
kAudioFormatMicrosoftGSM = 0x6D730031,
kAudioFormatAES3 = 'aes3',
kAudioFormatEnhancedAC3 = 'ec-3'
};
色彩二次抽样
经过大量的研究表明,人的眼睛对亮度非常敏感,但是对色彩信息比较迟钝。色彩二次抽样是指在原有的图片样本中,二次抽样,减少对色彩信息的抽样,而达到减小图片体积(样本数减小),又不怎么影响图片质量(眼睛对色彩不敏感)的效果。
视频数据使用的是YCbCr的颜色模型,YCbCr也称为YUV。其中Y表示亮度分量,Cb表示蓝色分量,Cr表示红色分量。
常用的YCbCr有4:4:4、4:2:2、4:2:0、4:1:1。
- 4:4:4 亮度和色彩信息的比值为1:1,所有色彩信息都会被抽样,也就是全彩。
- 4:2:2 亮度和色彩信息的比值为2:1,只有1/2的色彩信息被抽样
- 4:2:0和4:1:1 亮度和色彩信息比值为4:1,只有1/4的色彩信息被抽样
对应到AVFoundation的CVImageBuffer.h
中有:
CV_EXPORT const CFStringRef CV_NONNULL kCVImageBufferChromaSubsamplingKey __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_4_0); // CFString/CFNumber with one of the following values
CV_EXPORT const CFStringRef CV_NONNULL kCVImageBufferChromaSubsampling_420 __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_4_0);
CV_EXPORT const CFStringRef CV_NONNULL kCVImageBufferChromaSubsampling_422 __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_4_0);
CV_EXPORT const CFStringRef CV_NONNULL kCVImageBufferChromaSubsampling_411 __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_4_0);
一些特别专业的相机可能会用到4:4:4参数捕捉图片,大部分情况下会用4:2:2参数,普通的摄像头(如:iPhone摄像头)一般都是4:2:0、4:1:1
H.264
跟音频文件相比,视频文件体积更大。我们平时使用的视频文件都是经过压缩处理的。大部分音视频都使用编解码器(codec)来进行压缩和解压,iOS中使用的主要编解码器标准为H.264,H.264对应AVFoundation的AVVideoSettings.h
中:
AVF_EXPORT NSString *const AVVideoCodecKey /* NSString (CMVideoCodecType) */ NS_AVAILABLE(10_7, 4_0);
AVF_EXPORT NSString *const AVVideoCodecH264 /* @"avc1" */ NS_AVAILABLE(10_7, 4_0);
H.264通过空间和时间2个维度来压缩体积:
- 空间:空间上的压缩独立于视频帧,也称为帧内压缩。主要通过压缩图片的方式(如色彩二次抽样等)来减小体积,帧内压缩一般为有损压缩
- 时间:时间上的压缩也称为帧间压缩。视频是由连续的帧(图片)组成。一段视频中(很多张图片)有很多不变的冗余元素,通过减小这些冗余元素来达到压缩的目的,这就是帧间压缩,帧间压缩一般为无损压缩
H.264有3种profile,用于确定编码过程中帧间压缩使用的算法:
- BaseLine:这个标准提供了最低效的压缩,经过这个标准压缩后的文件体积任然比较大,但是这种算法计算强度最小
- Main:这个标准的计算强度比BaseLine大,但是能达到更高的压缩效果
- High:这个标准能达到最高质量的压缩效果,但他的压缩算法最复杂
H.264除了profile还有一个等级(Level)标准,Level是对自身特性的一些描述(码率,分辨率,fps等),Level越高,视频的码率、分辨率、fps越高。
对应AVfoundation的AVVideoSettings.h
中:
AVF_EXPORT NSString *const AVVideoProfileLevelKey /* NSString, H.264 only, one of: */ NS_AVAILABLE(10_8, 4_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264Baseline30 /* Baseline Profile Level 3.0 */ NS_AVAILABLE(10_8, 4_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264Baseline31 /* Baseline Profile Level 3.1 */ NS_AVAILABLE(10_8, 4_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264Baseline41 /* Baseline Profile Level 4.1 */ NS_AVAILABLE(10_8, 5_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264BaselineAutoLevel /* Baseline Profile Auto Level */ NS_AVAILABLE(10_9, 7_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264Main30 /* Main Profile Level 3.0 */ NS_AVAILABLE(10_8, 4_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264Main31 /* Main Profile Level 3.1 */ NS_AVAILABLE(10_8, 4_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264Main32 /* Main Profile Level 3.2 */ NS_AVAILABLE(10_8, 5_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264Main41 /* Main Profile Level 4.1 */ NS_AVAILABLE(10_8, 5_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264MainAutoLevel /* Main Profile Auto Level */ NS_AVAILABLE(10_9, 7_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264High40 /* High Profile Level 4.0 */ NS_AVAILABLE(10_9, 6_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264High41 /* High Profile Level 4.1 */ NS_AVAILABLE(10_9, 6_0);
AVF_EXPORT NSString *const AVVideoProfileLevelH264HighAutoLevel /* High Profile Auto Level */ NS_AVAILABLE(10_9, 7_0);
一些移动设备(手机、游戏机、PMP)由于性能有限,不支持全部高级视频压缩特性和高分辨率图像,只支持基础压缩特性和分辨率低一些的图像。
视频码率(bitRate)
码率是指单位时间内传输的数据位数。视频体积=视频码率*时间
,由此可见固定长度的视频,码率是决定大小的唯一因素。视频码率决定着视频的压缩效果,也决定了视频是质量。码率越高,质量越好,体积越大。码率越低,体积越小,视频质量也越差。
编码时,根据码率可以分为固定码率(CBR)编码和可变码率(VBR)编码。
- 固定码率:指编码器输出的码率一直为一个固定值,这种编码方式计算量小,编码速度快,但是编码效果不怎么好。对于画面变化大的视频片段,由于码率限制,导致视频非常模糊,然而对于画面变化小的片段,却会造成码率浪费。
- 可变码率:指编码器的输出码率可以根据编码器的输入源信号的复杂度自适应的调整,这种方式编码效果比较好
码率对应于AVFoundation中AVVideoSettings.h
:
AVF_EXPORT NSString *const AVVideoAverageBitRateKey /* NSNumber (bits per second, H.264 only) */ NS_AVAILABLE(10_7, 4_0);
Reference
AV Foundation 开发秘籍
iOS音频播放 (一):概述
H.264中profile和level
音频的位元深度
奈奎斯特频率