本文章是小编阅读这本书的一些摘录和笔记
希望自己能尽快读完,持续更新吧
第1章 AV Foundation 入门
1.1 AV Foundation 的含义
- 高度依赖多线程机制
- 充分利用多核硬件优势并大量使用block和Grand Central Dispatch(GCD)机制将复杂的计算进程放在后台线程运行。
1.2 AV Foundation 的适用范围
- Core Audio 推荐阅读《Leaning Core Audio》
- Core Video 数字视频所提供的管道模式,为相对的Core Media提供图片缓存和缓存池支持
- Core Media 低层级媒体管道的一部分,提供针对音频样本是视频帧处理所需的低层级数据类型和接口
- Core Animation 在视频编辑和播放过程中添加动画标题和图片效果
1.3 解析 AV Foundation
- 音频播放(AVAudioPlayer)和记录(AVAudioRecorder)
- 媒体文件检查:获取媒体资源技术参数,基于AVMetadataItem提供源数据支持
- 视频播放:本地或远程流,核心类AVPlayer和AVPlayerItem
- 媒体捕捉:摄像头捕捉核心类AVCaptureSession
- 媒体编辑:音视频组合、修改编辑媒体片段、修改音频参数、添加动画标题、场景切换效果
- 媒体处理:直接访问视频帧和音频样本(AVAssetReader和AVAssetWriter)
1.4 了解数字媒体
- 音视频模拟信号 -> 大脑电信号
- 模拟信号 -> 数字信号 (采样Sampling)
1.4.1 数字媒体采样
- 时间采样:捕捉一个信号周期内的变化
- 空间采样:可视化媒体
1.4.2 音频采样介绍
- 频率:震动的速率或频率决定了声音的音调
- 振幅:用来测量频率的相对强度,大致表示声音的音量
- 电动式麦克风(dynamic microphone):膜片感受到声音震动,带动线圈震动,产生同输入信号相同振幅和频率的电流信号
- 人类可接收到的音频范围:20Hz~20kHz
- 线型脉冲编码调制(linear pulse-code modulation,Linear PCM, LPCM):这个过程采样或测量一个固定的音频信号,过程的周期率被称为采样率。
- 未压缩视频存储需求举例:24位RGB色彩(R、G、B各占8位),分辨率1280×720,帧率30FPS,那么存储需求为79MB/s
1.5 数字媒体压缩
1.5.1 色彩二次抽样
- YUV(Y-Prime-C-B-C-R)(Y'CbCr'):适用色彩(颜色)通道UV替换了像素的亮度通道Y。如果除去亮度,剩下的就是一幅灰度图片。因此如果大幅减少存储在每个像素中的颜色信息,而不至于图片的质量受损,这个减少颜色数据的过程就成为色彩二次抽样。
- jab:这个比较难理解
1.5.2 编解码器压缩
1.5.3 视频编解码器
- H.264:规范是MPEG(Motion Picture Experts Group)所定义的MPEG-4的一部分。多用于消费者视频摄像头捕捉到的资源。通过帧内压缩和帧间压缩缩小视频文件的尺寸。
- Apple ProRes:是有损编解码器,只在OS X上可用。
- 此外AV Foundation还支持MPEG-1、MPEG-2、MPEG-4、H.263和DV等多种不同的视频捕捉设备的编解码器。
1.5.4 音频编解码器
- 高级音频编码(ACC):是H.264标准相应的音频处理方式。可在低比特率低前提下提供更高质量的音频。
1.6 容器格式
通常的文件后缀应被认为是文件的容器格式(containerformat),也是元文件格式,容器格式包含一种或更多种媒体类型的目录。
- QuickTime:
- MPEG-4:
1.7 初识 AV Foundation
使用AVSpeechSynthesizer
和AVSpeechUtterance
实现文本语音播放
第2章 播放和录制音频
2.1 Mac和iOS的音频环境
- 可管理的音频环境(managed audio environment)
- 音频会话(audio session)
2.2 理解音频会话
2.2.1 音频会话分类
AV Foundation 定义了7种分类来描述应用程序所使用的音频行为:
分类 | 作用 | 是否允许混音 | 音频输入 | 音频输出 |
---|---|---|---|---|
Ambient | 游戏、效率应用 | 是 | 是 | |
Solo Ambient(默认) | 游戏、效率应用 | 是 | ||
Playback | 音频和视频播放器 | 可选 | 是 | |
Record | 录音机、音频捕捉 | 是 | ||
Play and Record | VoIP、语音聊天 | 可选 | 是 | 是 |
Audio Processing | 离线会话和处理 | |||
Multi_Route | 使用外部硬件的高级 A/V 应用程序 | 是 | 是 |
2.2.2 配置音频会话
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 应用程序音频会话
AVAudioSession *session = [AVAudioSession sharedInstance]; // 单例
NSError *error;
// 设置分类
BOOL categoryPlayback = [session setCategory:AVAudioSessionCategoryPlayback error:&error];
if (!categoryPlayback) {
}
// 最后告知音频会话激活配置
BOOL isActive = [session setActive:YES error:&error];
if (!isActive) {
}
return YES;
}
2.3 使用 AVAudioPlayer 播放音频
AVAudioPlayer
类的实例提供了一种简单地从文本或内存中播放音频的方法。
AUAudioPlayer
构建于Core Audio
中的C-based Audio Queue Services的最顶层。
2.3.1 创建 AVAudioPlayer
有两种方法可以创建一个AudioPlayer,使用包含要播放音频的内存版本的NSData
,或本地音频文件的NSURL
。
// 通过本地音频的URL创建
NSURL *audioURL = [[NSBundle mainBundle] URLForResource:@"Sheep" withExtension:@"mp3"];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
// 如果返回一个有效的播放实例,建议开发者调用其prepareToPlay方法,
// 这样做会取得需要的音频硬件并预加载Audio Queue的缓冲区
// 调用prepareToPlay这个动作是可选的,当调用play方法时会隐形激活,不过在创建时准备播放器可以降低调用play方法和听到声音输出之间的延时
if (audioPlayer) {
[audioPlayer prepareToPlay];
}
// 播放音频
[audioPlayer play];
2.3.3 对播放进行控制
pause和stop方法对异同点:
- 相同:都可以暂停/停止当前播放的音频,下一时间调用play方法,音频都会继续播放;
- 不同:这两个方法最主要的却别在底层处理上。调用stop方法会撤销调用prepareToPlay时所做的设置,而调用pause方法则不会。
2.4 创建 Audio Looper
音频混合/混音
实例:(略)
2.5 配置音频会话
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// 音频会话设置
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error;
// 设置分类 后台播放(还需要在info.plist处添加Required background modes,并添加一项App plays audio or streams audio/video using airplay)
if (![audioSession setCategory:AVAudioSessionCategoryPlayback error:&error]) {
MYLog(@"音频会话分类设置错误:%@", [error localizedDescription]);
}
// 激活音频会话
if (![audioSession setActive:YES error:&error]) {
MYLog(@"音频会话激活失败:%@", [error localizedDescription]);
}
return YES;
}
2.6 处理中断事件
在控制器初始化时注册通知
// 注册中断通知
NSNotificationCenter *notif = [NSNotificationCenter defaultCenter];
[notif addObserver:self
selector:@selector(handleInterruption:)
name:AVAudioSessionInterruptionNotification
object:[AVAudioSession sharedInstance]];
注册了通知中心一定要记得在销毁时移除
- (void)dealloc {
// 移除通知
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
处理中断通知事件
#pragma mark - 处理中断通知
// 注意这里的参数不是NSNotificationCenter,而是推送过来的NSNotification
- (void)handleInterruption:(NSNotification *)notification {
NSDictionary *info = notification.userInfo;
// 中断类型(枚举)
AVAudioSessionInterruptionType interruptionType = [[info objectForKey:AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
switch (interruptionType) {
case AVAudioSessionInterruptionTypeBegan: // 中断开始
{
[self stop]; // 调用stop方法并不能停止播放,只能更新内部状态
if (self.delegate) {
[self.delegate playbackStoped];
}
}
break;
case AVAudioSessionInterruptionTypeEnded: // 中断结束
{
// 中断结束后,恢复音乐播放
// 音频会话是否已经重新激活、是否可以再次播放(只有中断结束才有这个options)
AVAudioSessionInterruptionOptions options = [[info objectForKey:AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
if (options == AVAudioSessionInterruptionOptionShouldResume) {
[self play];
if (self.delegate) {
[self.delegate playbackBegan];
}
}
}
break;
default:
break;
}
}
因为控制器参与处理页面,所以写个协议,设置委托来进行更新界面
@protocol THPlayerControllerDelegate
- (void)playbackStoped;
- (void)playbackBegan;
@end
2.7 对线路改变的响应
iOS设备上添加或移除音频输入、输出线路时,会发生线路改变。有多重原因会导致线路的变化,比如用户插入耳机或断开USB麦克风。当这些事件发生时,音频会根据情况改变输入或输出线路,同时AVAudioSession会广播一个描述该变化的通知给所有相关的侦听器。为了遵循Apple的Human Interface Guidelines(HIG)的相关定义,应用程序应该成为这些相关侦听器中的一员。
注册线路变化通知
// 注册线路通知
[notif addObserver:self
selector:@selector(handleRouteChange:)
name:AVAudioSessionRouteChangeNotification
object:[AVAudioSession sharedInstance]];
线路改变通知事件处理(耳机断开后停止播放)
// 线路改变通知事件处理
- (void)handleRouteChange:(NSNotification *)notification {
NSDictionary *info = notification.userInfo;
// 线路改变原因
AVAudioSessionRouteChangeReason reason = [[info objectForKey:AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue];
switch (reason) {
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: // 旧线路不能使用
{
// 前一个线路的描述
AVAudioSessionRouteDescription *previousRoute = [info objectForKey:AVAudioSessionRouteChangePreviousRouteKey];
// 线路描述信息 输出信息
AVAudioSessionPortDescription *previousOutput = [previousRoute.outputs firstObject];
// (输出)类型
NSString *portType = previousOutput.portType;
// 如果之前的线路耳机(即我们要拔掉耳机时),停止播放
if ([portType isEqualToString:AVAudioSessionPortHeadphones]) {
[self stop];
if (self.delegate) {
[self.delegate playbackStoped];
}
}
}
break;
default:
break;
}
}
2.8 使用 AVAudioRecorder 录制音频
音频会话设置
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// 音频会话设置
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error;
// 设置分类
// 录音
if (![audioSession setCategory:AVAudioSessionCategoryRecord error:&error]) {
MYLog(@"音频会话录音分类设置错误:%@", [error localizedDescription]);
}
// 激活音频会话
if (![audioSession setActive:YES error:&error]) {
MYLog(@"音频会话激活失败:%@", [error localizedDescription]);
}
return YES;
}