本文章是小編閱讀這本書的一些摘錄和筆記
希望自己能盡快讀完膘魄,持續(xù)更新吧
第1章 AV Foundation 入門
1.1 AV Foundation 的含義
- 高度依賴多線程機制
- 充分利用多核硬件優(yōu)勢并大量使用block和Grand Central Dispatch(GCD)機制將復雜的計算進程放在后臺線程運行赠叼。
1.2 AV Foundation 的適用范圍
- Core Audio 推薦閱讀《Leaning Core Audio》
- Core Video 數(shù)字視頻所提供的管道模式奶浦,為相對的Core Media提供圖片緩存和緩存池支持
- Core Media 低層級媒體管道的一部分尼荆,提供針對音頻樣本是視頻幀處理所需的低層級數(shù)據(jù)類型和接口
- Core Animation 在視頻編輯和播放過程中添加動畫標題和圖片效果
1.3 解析 AV Foundation
- 音頻播放(AVAudioPlayer)和記錄(AVAudioRecorder)
- 媒體文件檢查:獲取媒體資源技術(shù)參數(shù)际长,基于AVMetadataItem提供源數(shù)據(jù)支持
- 視頻播放:本地或遠程流想帅,核心類AVPlayer和AVPlayerItem
- 媒體捕捉:攝像頭捕捉核心類AVCaptureSession
- 媒體編輯:音視頻組合、修改編輯媒體片段队丝、修改音頻參數(shù)、添加動畫標題欲鹏、場景切換效果
- 媒體處理:直接訪問視頻幀和音頻樣本(AVAssetReader和AVAssetWriter)
1.4 了解數(shù)字媒體
- 音視頻模擬信號 -> 大腦電信號
- 模擬信號 -> 數(shù)字信號 (采樣Sampling)
1.4.1 數(shù)字媒體采樣
- 時間采樣:捕捉一個信號周期內(nèi)的變化
- 空間采樣:可視化媒體
1.4.2 音頻采樣介紹
- 頻率:震動的速率或頻率決定了聲音的音調(diào)
- 振幅:用來測量頻率的相對強度机久,大致表示聲音的音量
- 電動式麥克風(dynamic microphone):膜片感受到聲音震動,帶動線圈震動赔嚎,產(chǎn)生同輸入信號相同振幅和頻率的電流信號
- 人類可接收到的音頻范圍:20Hz~20kHz
- 線型脈沖編碼調(diào)制(linear pulse-code modulation膘盖,Linear PCM, LPCM):這個過程采樣或測量一個固定的音頻信號,過程的周期率被稱為采樣率尤误。
- 未壓縮視頻存儲需求舉例:24位RGB色彩(R侠畔、G、B各占8位)损晤,分辨率1280×720软棺,幀率30FPS,那么存儲需求為79MB/s
1.5 數(shù)字媒體壓縮
1.5.1 色彩二次抽樣
- YUV(Y-Prime-C-B-C-R)(Y'CbCr'):適用色彩(顏色)通道UV替換了像素的亮度通道Y尤勋。如果除去亮度喘落,剩下的就是一幅灰度圖片。因此如果大幅減少存儲在每個像素中的顏色信息最冰,而不至于圖片的質(zhì)量受損瘦棋,這個減少顏色數(shù)據(jù)的過程就成為色彩二次抽樣。
- jab:這個比較難理解
1.5.2 編解碼器壓縮
1.5.3 視頻編解碼器
- H.264:規(guī)范是MPEG(Motion Picture Experts Group)所定義的MPEG-4的一部分暖哨。多用于消費者視頻攝像頭捕捉到的資源赌朋。通過幀內(nèi)壓縮和幀間壓縮縮小視頻文件的尺寸。
- Apple ProRes:是有損編解碼器鹿蜀,只在OS X上可用箕慧。
- 此外AV Foundation還支持MPEG-1、MPEG-2茴恰、MPEG-4颠焦、H.263和DV等多種不同的視頻捕捉設備的編解碼器。
1.5.4 音頻編解碼器
- 高級音頻編碼(ACC):是H.264標準相應的音頻處理方式往枣》ネィ可在低比特率低前提下提供更高質(zhì)量的音頻。
1.6 容器格式
通常的文件后綴應被認為是文件的容器格式(containerformat)分冈,也是元文件格式圾另,容器格式包含一種或更多種媒體類型的目錄。
- QuickTime:
- MPEG-4:
1.7 初識 AV Foundation
使用AVSpeechSynthesizer
和AVSpeechUtterance
實現(xiàn)文本語音播放
第2章 播放和錄制音頻
2.1 Mac和iOS的音頻環(huán)境
- 可管理的音頻環(huán)境(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
類的實例提供了一種簡單地從文本或內(nèi)存中播放音頻的方法扰路。
AUAudioPlayer
構(gòu)建于Core Audio
中的C-based Audio Queue Services的最頂層尤溜。
2.3.1 創(chuàng)建 AVAudioPlayer
有兩種方法可以創(chuàng)建一個AudioPlayer,使用包含要播放音頻的內(nèi)存版本的NSData
汗唱,或本地音頻文件的NSURL
宫莱。
// 通過本地音頻的URL創(chuàng)建
NSURL *audioURL = [[NSBundle mainBundle] URLForResource:@"Sheep" withExtension:@"mp3"];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
// 如果返回一個有效的播放實例,建議開發(fā)者調(diào)用其prepareToPlay方法哩罪,
// 這樣做會取得需要的音頻硬件并預加載Audio Queue的緩沖區(qū)
// 調(diào)用prepareToPlay這個動作是可選的授霸,當調(diào)用play方法時會隱形激活,不過在創(chuàng)建時準備播放器可以降低調(diào)用play方法和聽到聲音輸出之間的延時
if (audioPlayer) {
[audioPlayer prepareToPlay];
}
// 播放音頻
[audioPlayer play];
2.3.3 對播放進行控制
pause和stop方法對異同點:
- 相同:都可以暫停/停止當前播放的音頻际插,下一時間調(diào)用play方法碘耳,音頻都會繼續(xù)播放;
- 不同:這兩個方法最主要的卻別在底層處理上腹鹉。調(diào)用stop方法會撤銷調(diào)用prepareToPlay時所做的設置藏畅,而調(diào)用pause方法則不會敷硅。
2.4 創(chuàng)建 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 - 處理中斷通知
// 注意這里的參數(shù)不是NSNotificationCenter绞蹦,而是推送過來的NSNotification
- (void)handleInterruption:(NSNotification *)notification {
NSDictionary *info = notification.userInfo;
// 中斷類型(枚舉)
AVAudioSessionInterruptionType interruptionType = [[info objectForKey:AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
switch (interruptionType) {
case AVAudioSessionInterruptionTypeBegan: // 中斷開始
{
[self stop]; // 調(diào)用stop方法并不能停止播放力奋,只能更新內(nèi)部狀態(tài)
if (self.delegate) {
[self.delegate playbackStoped];
}
}
break;
case AVAudioSessionInterruptionTypeEnded: // 中斷結(jié)束
{
// 中斷結(jié)束后,恢復音樂播放
// 音頻會話是否已經(jīng)重新激活幽七、是否可以再次播放(只有中斷結(jié)束才有這個options)
AVAudioSessionInterruptionOptions options = [[info objectForKey:AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
if (options == AVAudioSessionInterruptionOptionShouldResume) {
[self play];
if (self.delegate) {
[self.delegate playbackBegan];
}
}
}
break;
default:
break;
}
}
因為控制器參與處理頁面,所以寫個協(xié)議,設置委托來進行更新界面
@protocol THPlayerControllerDelegate <NSObject>
- (void)playbackStoped;
- (void)playbackBegan;
@end
2.7 對線路改變的響應
iOS設備上添加或移除音頻輸入披蕉、輸出線路時妖爷,會發(fā)生線路改變。有多重原因會導致線路的變化驶鹉,比如用戶插入耳機或斷開USB麥克風绩蜻。當這些事件發(fā)生時,音頻會根據(jù)情況改變輸入或輸出線路室埋,同時AVAudioSession會廣播一個描述該變化的通知給所有相關(guān)的偵聽器办绝。為了遵循Apple的Human Interface Guidelines(HIG)的相關(guān)定義,應用程序應該成為這些相關(guān)偵聽器中的一員姚淆。
注冊線路變化通知
// 注冊線路通知
[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;
}