iOS視頻編解碼_1

我們將分成以下幾點(diǎn)討論視頻編解碼的情況

1、收到H.264格式的視頻數(shù)據(jù)并在應(yīng)用中播放

2、收到H.264視頻數(shù)據(jù)在應(yīng)用中播放的同時(shí)得到每一幀圖片

3、從相機(jī)或者其他地方收到視頻時(shí)將它壓縮成視頻文件

4、收到視頻時(shí)將它壓縮成視頻文件的同時(shí)得到每一幀壓縮數(shù)據(jù)并將它通過(guò)網(wǎng)絡(luò)發(fā)送出去

音視頻接口梗概:

AVKit:提供一些方便使用的上層接口,在View層上提供接口處理音視頻

AVFoundation:在AVKit下面一層,提供更廣的接口來(lái)處理音視頻任務(wù),它提供了可以直接解碼視頻并且在layer上播放的接口,也提供了直接壓縮視頻生成視頻文件的接口

Video Toolbox:它提供直接對(duì)接編碼器和解碼器的接口,可以將壓縮的視頻流解碼成CV pixel buffers,也可以將原始視頻壓縮成CM sample buffers

Core Media, Core Video:最底層接口,提供許多必要類型

在iOS上,AVKit,AVFoundation,Video Toolbox都使用硬件解碼

音視頻接口中的一些常見(jiàn)類型

CVPixelBuffer:它包含圖像本身數(shù)據(jù),包含圖像長(zhǎng)寬信息,像素格式等

CVPixelBufferPool:它允許我們循環(huán)使用CVPixelBuffer,由于持續(xù)的生成和銷毀CVPixelBuffer會(huì)占用大量資源,所以將它放入池子中可以循環(huán)使用

pixelBufferAttributes:它在音視頻接口中是一個(gè)常見(jiàn)對(duì)象,是一個(gè)CF字典包含了CVPixelBuffer和PixelBufferPool需要的一系列數(shù)據(jù),例如長(zhǎng)寬,像素格式等

CMTime:用來(lái)描述時(shí)間的類型,所以它是一個(gè)有理數(shù)

CMVideoFormatDescription:是一個(gè)描述視頻數(shù)據(jù)的類型,包括長(zhǎng)寬,像素格式信息,它還有一些擴(kuò)展,例如像素橫縱比,色域。在H.264數(shù)據(jù)中,參數(shù)設(shè)置也包含在這些擴(kuò)展中

CMBlockBuffer:它可以包含任意的Core Media中的數(shù)據(jù)。通常情況下,視頻數(shù)據(jù),壓縮視頻數(shù)據(jù)都會(huì)打包放在這個(gè)類型中

CMSampleBuffer:它可以打包壓縮視頻幀或未壓縮視頻幀。還包含許多上面提到的類型,例如CMTime,用來(lái)描述當(dāng)前幀在視頻中的時(shí)間點(diǎn),CMVideoFormatDescription,用來(lái)描述CMSampleBuffer中的數(shù)據(jù)。最后,其中還包含了視頻本身的數(shù)據(jù),我們把壓縮的視頻數(shù)據(jù)放入CMBlockBuffer中,未壓縮的可以放在CVPixelBuffer中,也可以同樣放在CMBlockBuffer中

CMClock:這個(gè)時(shí)間類型難以控制,它會(huì)一直以一個(gè)確定的頻率走著。所以我們引入CMTimebase來(lái)對(duì)CMClock提供更多的控制。

CMTimebase:我們可以基于hostTime clock來(lái)創(chuàng)建CMTimebase,然后設(shè)置時(shí)間為0,它會(huì)與CMClock的當(dāng)前時(shí)間映射,我們還可以設(shè)置rate,當(dāng)rate設(shè)置為1時(shí),timebase會(huì)與clock的頻率一致。CMTimebase也可以基于其他的CMTimebase建立

接下來(lái)我們討論第一種情況

收到H.264格式的視頻數(shù)據(jù)并在應(yīng)用中播放

當(dāng)我們收到網(wǎng)絡(luò)中傳來(lái)的視頻數(shù)據(jù)時(shí),我們可以使用AVSampelBufferDisplayLayer這個(gè)類型對(duì)象來(lái)進(jìn)行播放。這是從iOS 8中引入的新類型。

在AVSampelBufferDisplayLayer中,需要壓縮的視頻幀是CMSampleBuffer格式的,再通過(guò)解碼器把它變成CVPixelBuffer格式,并且按順序排好,等待在合適的時(shí)間展示到屏幕上。但是,當(dāng)從網(wǎng)絡(luò)中獲取視頻數(shù)據(jù)時(shí),許多時(shí)候它是elementary stream格式的。所以我們需要將它變成CMSampleBuffer格式。

H.264定義了一些打包方式,第一種是Elementary Stream packaging,還有一種是MPEG-4 packaging,它用在視頻文件,MP4文件中。在CMSampleBuffer,Core Media和AVFoundation中只接受MPEG-4 packaging類型的數(shù)據(jù)。

H.264數(shù)據(jù)流中的數(shù)據(jù)都打包在一系列NAL單元中,NAL單元可以包含一幀的數(shù)據(jù),一幀數(shù)據(jù)也可能跨越多個(gè)NAL單元。NAL單元還可能包含參數(shù)設(shè)置信息,Sequence Parameter Set和Picture Parameter Set,這些參數(shù)提供給解碼器使用來(lái)解碼接下來(lái)的幀數(shù)據(jù),直到新的參數(shù)設(shè)置數(shù)據(jù)傳入。

在Elementary Stream packaging中,參數(shù)設(shè)置是包含在NAL單元中的。在MPEG-4中,參數(shù)設(shè)置被抽離出來(lái)單獨(dú)放在CMVideoFormatDescription中,這種方式允許我們可以隨機(jī)跳到視頻中的某一位置并從I幀開(kāi)始解碼播放。

所以當(dāng)我們獲取到Elementary Stream時(shí),iOS提供了CMVideoFormatDescriptionCreatefromH264ParameterSets這個(gè)方法來(lái)將Parameter Set打包成CMVideoFormatDescription。

Elementary Stream和MPEG-4 Stream的另一個(gè)不同點(diǎn)在NAL header中,Elementary Stream的NAL header中有3到4個(gè)字節(jié)的start code,而在MPEG-4的NAL header中是4字節(jié)的length code。

接下來(lái)我們討論如何從Elementary Stream中創(chuàng)建一個(gè)CMSampleBuffer。首先把NAL Unit中的start code替換成length code,然后將它加入CMBlockBuffer中。然后獲取parameter sets生成CMVideoFormatDescription。最后加入CMTime值,它代表當(dāng)前幀的時(shí)間。接下來(lái)使用CMSampleBufferCreate這個(gè)方法創(chuàng)建CMSampleBuffer。

接下來(lái)基于hostTime clock創(chuàng)建一個(gè)timebase。然后將它設(shè)置成AVSampleBufferDisplayLayer中的controlTimebase。

當(dāng)使用sampleBufferDisplayerLayer時(shí),有兩種使用場(chǎng)景,第一種是視頻幀以一定的速率接收并播放,這種情況出現(xiàn)在直播或者視頻會(huì)議中。另一種是有大量的CMSampleBuffers等待被sampleBufferDisplayerLayer接收處理,這種情況在我們有大量的網(wǎng)絡(luò)緩存數(shù)據(jù)或者從一個(gè)視頻文件中讀取數(shù)據(jù)中出現(xiàn)。

第一種情況,當(dāng)幀數(shù)據(jù)以一定頻率被接收時(shí),我們使用enqueueSampleBuffer來(lái)接收它們。

第二種情況,當(dāng)我們有大量的幀數(shù)據(jù)時(shí),我們不能一下子把所有數(shù)據(jù)都加入sampleBufferDisplayerLayer中,而是當(dāng)sampleBufferDisplayerLayer中的buffers很少時(shí),當(dāng)它需要更多的buffers時(shí),我們才添加新的幀數(shù)據(jù)。我們使用requestMediaDataWhenReadyOnQueue這個(gè)方法來(lái)檢測(cè)sampleBufferDisplayerLayer中的幀數(shù)據(jù)是否不足,它提供了一個(gè)代碼塊,當(dāng)數(shù)據(jù)不足時(shí)會(huì)調(diào)用該代碼塊。

通過(guò)上面的學(xué)習(xí),我們了解了如何創(chuàng)建一個(gè)AVSampleBufferDisplayLayer。

如何將H.264 elementary stream轉(zhuǎn)化成CMSampleBuffers。

如何將CMSampleBuffers提供給AVSampleBufferDisplayLayer使用。

以及如何配合CMTimebase來(lái)使用AVSampleBufferDisplayLayer。


本文翻譯自WWDC14:Direct Access to Video Encoding and Decoding

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容