前言
相關(guān)文章:
使用VideoToolbox硬編碼H.264
使用VideoToolbox硬解碼H.264
使用AudioToolbox編碼AAC
使用AudioToolbox播放AAC
HLS點播實現(xiàn)(H.264和AAC碼流)
HLS推流的實現(xiàn)(iOS和OS X系統(tǒng))
iOS在線音頻流播放
Audio Unit播放PCM文件
Audio Unit錄音(播放伴奏+耳返)
Audio Unit播放aac/m4a/mp3等文件
Audio Unit和ExtendedAudioFile播放音頻
AUGraph結(jié)合RemoteI/O Unit與Mixer Unit
上面的文章介紹了音視頻信息的加載和解析,在另外的《OpenGLES文集》也詳細(xì)介紹了OpenGL如何繪制圖像。
這次結(jié)合Audio Unit和OpenGL ES,分別加載多媒體文件的音頻和視頻信息并播放。
正文
整體思路
demo包括三大部分,分別是資源加載、音頻播放、視頻播放。
- 資源加載:是用
AVURLAsset
加載資源文件,再創(chuàng)建資源讀取器AVAssetReader
,然后附加音頻讀取接口mReaderAudioTrackOutput
和視頻讀取接口mReaderVideoTrackOutput
到資源讀取器。 - 音頻播放 :從音頻讀取接口
mReaderAudioTrackOutput
加載音頻信息得到CMSampleBuffer
,用方法CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer
把音頻數(shù)據(jù)轉(zhuǎn)成AudioBufferList
格式,再采用AudioUnit播放; - 視頻播放:從視頻讀取接口
mReaderVideoTrackOutput
加載視頻信息得到CMSampleBuffer
,用方法CMSampleBufferGetImageBuffer
把視頻數(shù)據(jù)轉(zhuǎn)成CVPixelBufferRef
格式,再用OpenGL ES繪制圖像;
整體流程圖
具體解析
1、資源加載
資源加載用的是AVFoundation
提供的方法,先加載音視頻的軌道信息。
然后初始化好音視頻的格式信息outputSettings
,outputSettings
是AVAssetReaderTrackOutput
初始化的必要條件之一。
注意音軌和聲道的區(qū)別,比如說在ktv唱歌的時候,通常伴奏是一個音軌,錄到的人聲是一個音軌,最后播放的時候進(jìn)行混合。而聲道我們常用聲道數(shù)的概念,指的是聲音播放時的揚(yáng)聲器數(shù)量。
音軌=AudioTrack
聲道=AudioChannel
2、音頻播放
音頻播放功能用的是Audio Unit,其中的RemoteIO Unit只能接受PCM數(shù)據(jù),故而要求讀取出來的音頻信息必須是PCM格式的,并且設(shè)置給Audio Unit的格式需要與outputSettings
一致。
3、視頻播放
視頻播放其實就是圖像信息的繪制,從資源我們可以讀取到圖像信息,再把圖像傳給已經(jīng)封裝好的LYOpenGLView類,就可以繪制圖像。圖像信息占用內(nèi)存較為明顯,需要注意內(nèi)存的回收。
遇到的問題
1、確定Audio Unit音頻格式
嘗試加載資源文件的音頻格式并設(shè)置給Audio Unit,但因為Audio Unit無法接受資源文件的格式(大多數(shù)文件的音頻文件格式為AAC)。
解決方案是直接設(shè)置讀取的音頻格式信息為PCM,并且手動初始化ASBD,保證兩端的格式一致。
如下,是資源文件的音頻讀取格式和手動初始化的格式:
NSMutableDictionary *outputSettings = [NSMutableDictionary dictionary];
[outputSettings setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
[outputSettings setObject:@(16) forKey:AVLinearPCMBitDepthKey];
[outputSettings setObject:@(NO) forKey:AVLinearPCMIsBigEndianKey];
[outputSettings setObject:@(NO) forKey:AVLinearPCMIsFloatKey];
[outputSettings setObject:@(YES) forKey:AVLinearPCMIsNonInterleaved];
[outputSettings setObject:@(44100.0) forKey:AVSampleRateKey];
[outputSettings setObject:@(1) forKey:AVNumberOfChannelsKey];
AudioStreamBasicDescription inputFormat;
inputFormat.mSampleRate = 44100;
inputFormat.mFormatID = kAudioFormatLinearPCM;
inputFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsNonInterleaved;
inputFormat.mFramesPerPacket = 1;
inputFormat.mChannelsPerFrame = 1;
inputFormat.mBytesPerPacket = 2;
inputFormat.mBytesPerFrame = 2;
inputFormat.mBitsPerChannel = 16;
self.fileFormat = inputFormat;
2、音視頻同步
demo中存在兩個變量self.mAudioTimeStamp
和self.mVideoTimeStamp
,分別表示音頻播放和視頻播放的時間戳。
其中音頻播放進(jìn)度由Audio Unit驅(qū)動,視頻播放進(jìn)度由CADisplayLink驅(qū)動,為了保證視頻進(jìn)度不超過音頻進(jìn)度,添加了if (self.mVideoTimeStamp < self.mAudioTimeStamp)
的判斷。
但在模擬器運(yùn)行的時候,視頻的解析比音頻解析的速度小很多,造成較為明顯的不同步。
在真機(jī)運(yùn)行的時候,這種現(xiàn)象有明顯的改進(jìn)。
目前還沒找到較好的同步方式,如果有知道請指教。
總結(jié)
本文沒有擴(kuò)展更多的音頻和視頻知識,通過結(jié)合三個部分知識,組成基本的音視頻播放流程。
由于時間原因,所做的技術(shù)預(yù)研無法盡善盡美,代碼沒有很好的打磨。
demo更多是實踐某些想法,如果代碼存在問題,懇請指出,幫助你我他少踩一些坑。