經過麥克風攝像頭採集音視頻數據
複製代碼
AVAudioSession *session = [AVAudioSession sharedInstance];
// 監聽聲音路線改變
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(handleRouteChange:)
name: AVAudioSessionRouteChangeNotification
object: session];
// 監聽聲音被打斷
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(handleInterruption:)
name: AVAudioSessionInterruptionNotification
object: session];
/// 建立AudioComponent
AudioComponentDescription acd;
acd.componentType = kAudioUnitType_Output;
//acd.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
acd.componentSubType = kAudioUnitSubType_RemoteIO;
acd.componentManufacturer = kAudioUnitManufacturer_Apple; // 廠商 直接寫kAudioUnitManufacturer_Apple
acd.componentFlags = 0; // 沒有明確值時必須設爲0
acd.componentFlagsMask = 0; // 沒有明確值時必須設爲0
self.component = AudioComponentFindNext(NULL, &acd);
OSStatus status = noErr;
status = AudioComponentInstanceNew(self.component, &_componetInstance);
if (noErr != status) {
[self handleAudioComponentCreationFailure];
}
/// 鏈接麥克風
UInt32 flagOne = 1;
AudioUnitSetProperty(self.componetInstance, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &flagOne, sizeof(flagOne));
AudioStreamBasicDescription desc = {0};
desc.mSampleRate = _configuration.audioSampleRate; // 採樣率
desc.mFormatID = kAudioFormatLinearPCM;
desc.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
desc.mChannelsPerFrame = (UInt32)_configuration.numberOfChannels;
desc.mFramesPerPacket = 1;
desc.mBitsPerChannel = 16; // 表示每一個聲道的音頻數據要多少位,一個字節是8位,因此用8 * 每一個採樣的字節數
desc.mBytesPerFrame = desc.mBitsPerChannel / 8 * desc.mChannelsPerFrame;
desc.mBytesPerPacket = desc.mBytesPerFrame * desc.mFramesPerPacket; // 根據mFormatFlags指定的Float類型非交錯存儲,就設置爲bytesPerSample表示每一個採樣的字節數。但若是是Interleaved交錯存儲的,就應該設置爲bytesPerSample * mChannelsPerFrame 由於左右聲道數據是交錯存在一塊兒的。
// 鏈接揚聲器
AudioUnitSetProperty(self.componetInstance, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desc, sizeof(desc));
// 設置聲音回調
AURenderCallbackStruct cb;
cb.inputProcRefCon = (__bridge void *)(self);
cb.inputProc = handleInputBuffer;
AudioUnitSetProperty(self.componetInstance, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 1, &cb, sizeof(cb));
// 初始化AudioComponentInstance
status = AudioUnitInitialize(self.componetInstance);
if (noErr != status) {
[self handleAudioComponentCreationFailure];
}
[session setPreferredSampleRate:_configuration.audioSampleRate error:nil];
/// AVAudioSessionCategoryPlayAndRecord 支持音頻播放和錄音、打斷其餘不支持混音APP、不會被靜音鍵或鎖屏鍵靜音
/// AVAudioSessionCategoryOptionDefaultToSpeaker 系統會自動選擇最佳的內置麥克風組合支持視頻聊天。
/// AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers 支持和其餘APP音頻混合
[session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers error:nil];
[session setActive:YES withOptions:kAudioSessionSetActiveFlag_NotifyOthersOnDeactivation error:nil];
[session setActive:YES error:nil];
複製代碼
音頻配置:碼率(128)和採樣率(44100HZ)
視頻配置:視頻分辨率(720P )、碼率(2000KB/S)和幀率(30FPS)
複製代碼
蘋果默認是 PCMweb
aac 是爲了取代 MP3,壓縮了原始文件,可是取決於比特率,合適的比特率人耳分辨不出算法
將數據採集的輸入流進行實時濾鏡, 美顏
複製代碼
特效濾鏡處理緩存
GPUImage (開源) 只有iOS 小型的能夠作 封裝和思惟基於 OpenGL ES服務器
Metal 蘋果 新開發的markdown
OpenGL PCsession
OpenGL ES 線路 手機框架
AudioToolBox FFmpeg AACide
軟解碼:使用 fdk_aac 將 PCM 轉爲 AAC
複製代碼
人耳掩蓋效應:去除冗餘信息ui
目前使用有損壓縮比較多編碼
有損壓縮:解壓後的數據徹底能夠復原
有損壓縮:解壓後的數據不能徹底復原,會丟失一部分信息,壓縮比越大,丟失的信息越多,信號還原的失真就好越大
VideoToolBox FFmpeg H264
軟編碼: FFmpeg X264
用到CPU
硬編碼 VideoToolBox AudioToolBox
商業項目 通用 硬編碼
GPU (運算大於CPU)
硬件加速器
視頻編碼 VideoToolBox FFmpeg H264
音頻編碼 AudioToolBox FFmpeg AAC
複製代碼
YUV 而不是用 rgba
1s 內 60張照片
10張爲一組 進行壓縮
取第一幀爲I幀,後面稱之爲 P幀,只保留和前一幀的不一樣點
B 幀 是保留和後一幀的差別。
爲了追求高壓縮(如小視頻),可以使用 I P B
可是直播是爲了追求高實時性,所以使用I P,而不使用B幀
複製代碼
VTCompressionSessionCreate
複製代碼
經過 AVFoundation 獲取捕獲結果回調
原始數據封裝爲 CVPixelBuffers,
CVPixelBuffers 爲主內存存儲的全部像素點數據的對象
複製代碼
encode 爲 CMSampleBuffers
六、將數據寫入 H264 文件 獲取到 SPS/PPS, 第一幀寫入 SPS/PPS VideoToolBox 在沒一個關鍵幀前面都會輸出 SPS/PPS信息,若是本幀爲關鍵幀,則能夠取出對應的 PPS / SPS 信息。
將採集的音視頻信息經過流媒體協議發送到流媒體服務器
複製代碼
數據分發 CDN
截屏
錄製
實時轉碼
負責拉流、解碼和播放
複製代碼
拉流:
音視頻解碼
相對於 HLS 來講,採用 RTMP 協議時,從採集推流端到流媒體服務器再到播放端是一條數據流,所以在服務器不會有落地文件。這樣 RTMP 相對來講就有這些優勢:
延時較小,一般爲 1-3s。
基於 TCP 長鏈接,不須要屢次建連。
所以業界大部分直播業務都會選擇用 RTMP 做爲流媒體協議。一般會將數據流封裝成 FLV 經過 HTTP 提供出去。可是這樣也有一些問題須要解決:
iOS 平臺沒有提供原生支持 RTMP 或 HTTP-FLV 的播放器,這就須要開發支持相關協議的播放器。
複製代碼
HLS 的基本原理就是當採集推流端將視頻流推送到流媒體服務器時,服務器將收到的流信息每緩存一段時間就封包成一個新的 ts 文件,同時服務器會創建一個 m3u8 的索引文件來維護最新幾個 ts 片斷的索引。當播放端獲取直播時,它是從 m3u8 索引文件獲取最新的 ts 視頻文件片斷來播放,從而保證用戶在任什麼時候候鏈接進來時都會看到較新的內容,實現近似直播的體驗。相對於常見的流媒體直播協議,例如 RTMP 協議、RTSP 協議等,HLS 最大的不一樣在於直播客戶端獲取到的並非一個完整的數據流,而是連續的、短時長的媒體文件,客戶端不斷的下載並播放這些小文件。這種方式的理論最小延時爲一個 ts 文件的時長,通常狀況爲 2-3 個 ts 文件的時長。HLS 的分段策略,基本上推薦是 10 秒一個分片,這就看出了 HLS 的缺點:
一般 HLS 直播延時會達到 20-30s,而高延時對於須要實時互動體驗的直播來講是不可接受的。
HLS 基於短鏈接 HTTP,HTTP 是基於 TCP 的,這就意味着 HLS 須要不斷地與服務器創建鏈接,TCP 每次創建鏈接時的三次握手、慢啓動過程、斷開鏈接時的四次揮手都會產生消耗。
不過 HLS 也有它的優勢:
數據經過 HTTP 協議傳輸,因此採用 HLS 時不用考慮防火牆或者代理的問題。
使用短時長的分片文件來播放,客戶端能夠平滑的切換碼率,以適應不一樣帶寬條件下的播放。
HLS 是蘋果推出的流媒體協議,在 iOS 平臺上能夠得到自然的支持,採用系統提供的 AVPlayer 就能直接播放,不用本身開發播放器。
image
複製代碼
先經過服務器將FLV下載到本地緩存,而後再經過NetConnection的本地鏈接來播放這個FLV,這種方法是播放本地的視頻,並非播放服務器的視頻。所以在本地緩存裏能夠找到這個FLV。其優勢就是服務器下載完這個FLV,服務器就沒有消耗了,節省服務器消耗。其缺點就是FLV會緩存在客戶端,對FLV的保密性很差。
是一種將直播流模擬成FLV文件,經過HTTP協議進行下載的模式來實現流媒體傳輸的協議,端口號80
通常建議使用HTTP FLV,實時性和RTMP相等。
優勢:HTTP相比於RTMP省去了一些協議交互時間,首屏時間更短。HTTP可拓展的功能更多。
複製代碼