視訊工具箱和硬體加速

發表於2015-06-08

在 OS X 和 iOS 裝置上進行視訊解碼的過程是比較複雜的。

為了詳細瞭解編解碼過程中所發生的事情,我們首先要了解一些基本概念。這樣才能去挖掘具體的實現細節。

Mac 硬體加速解碼的簡史

用 CPU 處理視訊的代價非常昂貴,而且編解碼器也非常複雜。軟解碼的流行是具有革命意義的。隨著 90 年代早期 QuickTime 1.0 和它的基於 C 語言的 API 的出現,你可以播放一個縮圖那麼大的視訊,每個畫素最多有 32,768 種可能的顏色,它們完全由 CPU 進行解碼。在當時,只有具有專門的圖形硬體的計算機才能播放彩色視訊。

圖片來源

到 20 世紀末,使用了當時最先進的 MPEG-2 視訊解碼器 的 DVD 被引進千家萬戶。隨後,蘋果將 DVD 驅動器加到了 PowerBooks (MacBook 的前身,2006 年停產),但是卻發現了一個問題:電腦電池和 G3 PowerPC CPU 的配合不夠高效,充一次電居然沒辦法播放完一整部 DVD 視訊。解決方案是在主機板上新增一個 C-Cube 生產的專用解碼晶片,來處理這些繁重的事務。這款晶片可以在 Wallstreet,Lombard 和 Pismo 三款 PowerBook 上找到,也可以在它們所對應的專業級的桌面電腦上找到。

蘋果從沒有提供公共 API,所以在 2001 年 Mac OS X 問世之前 DVD 只能限制在自帶的應用程式中播放。而從 Mac OS X 開始它就不再包含 DVD 播放程式了。

我們所知道的 DVD 播放器是在 OS X 10.1 開始引入的。在此之前,只能使用像 VLC 這樣的第三方軟體在 OS X 上播放 DVD。

到了 21 世紀初,CPU 和 電池的發展足以獨立解碼 MPEG-2,而不再需要一個專門的晶片 —— 至少只要沒有特別消耗資源的程式執行在後臺 (比如 Mail.app 這樣不斷地請求一個遠端伺服器的程式)。

在 00 年代中期,一個新生兒出現了,並且佔據了著鐳射讀取,數字電視廣播,以及線上視訊編解碼的主導地位:它就是H.264/AVC/MPEG-4 Part 10。相比前幾代,MPEG 的第四代編解碼技術有效地降低了頻寬需求。然而這是有代價的:增加了 CPU 負擔以及對專用解碼硬體的需求,特別是在像 iPhone 這樣的嵌入式裝置裡這個要求尤為明顯。若不使用專門的數字訊號處理器 (DSP),電池的壽命會急劇下降,通常會增至 2.5 倍的能耗 —— 哪怕是使用最高效的的軟體解碼技術。

隨著 QTKit 這個 Cocoa 封裝的 QuickTime API 在 OS X 10.5 Leopard 上的出現,蘋果公開了一個高效率的軟體解碼器。這是用匯編語言深度優化的,並且得益於在 WWDC 2008 大會上演示過的 clang 編譯器的開發,這個解碼器的效能在 OS X 10.6 中得到了進一步的提升。蘋果公司當時沒有提到一個潛在的能力 —— 根據可用性和解碼配置的相容性,可以動態切換到硬體解碼。這個特性是基於兩個新引入的私有框架:視訊工具箱 (Video Toolbox) 和視訊解碼加速 (Video Decode Acceleration, VDA)。

2008 年,Adobe 從原來的解碼器 (Sorenson Spark, On2 TrueMotion VP6) 切換到 H.264 上面,並且開始在它的跨平臺播放器上整合硬體加速解碼。對於 OS X,Adobe 的團隊發現所需要的底層技術都是存在的,並被部署在基於蘋果的 QTKit 框架的應用程式裡,但是蘋果不對外開放。蘋果公司在 OS X 10.6.3 上有所改變,蘋果釋出了一個針對 10.6 SDK 的補丁,裡面為 VDA 新增了一個標頭檔案。

VDA 裡面有什麼?這是一個封裝了 H.264 硬體解碼器的小框架,它可能工作也可能不工作,這取決於它是否能處理所提供的編碼資料的輸入緩衝。如果解碼器可以處理上述請求,它將返回解碼的幀,否則會話建立失敗,或者不返回幀而只返回一個錯誤碼。這裡有四種不同的錯誤狀態 (kVDADecoderHardwareNotSupportedErrkVDADecoderFormatNotSupportedErr,kVDADecoderConfigurationErrorkVDADecoderDecoderFailedErr),哪個都不是特別詳細。除去僅有的標頭檔案,既沒有官方文件,也沒有備用的解決方案。

快進到現在:在 iOS 8 和 OS X 10.8,蘋果開放了完整的視訊工具箱框架。這就像一頭野獸!它可以實時編解碼視訊甚至更快。你可以啟用或者禁用硬體加速的視訊解碼,甚至可以中途改變。但是文件並不那麼讓人滿意:這個框架有 14 個標頭檔案,Xcode 文件中只寫有一句話 “請移步標頭檔案”

此外,如果沒有實際的測試,就沒有辦法知道所支援的編解碼器,編解碼配置,或者在任意裝置上可用的解碼位元率。因此,大量的測試和裝置專用的程式碼是有必要的。內部來看,它和原始的 QuickTime 模組的實現很相似。外部 API 在不同作業系統和平臺上是相同的,但實際可用的特性是不一定的。

A4 到 A6 的 iOS 裝置是支援 H.264/AVC/MPEG-4 Part 10 (until profile 100 and up to level 5.1),MPEG-4 Part 2 和 H.263 的。

A7 加入了對 H.264’s profile 110 的支援,它允許各個顏色通道從 8 位編碼增加到 10 位,這使更高階別的色彩細節成為可能。這個功能通常用於電視臺或者媒體編輯行業。

A8 似乎是包含第五代解碼器 HEVC / H.265 的支援,這在支援 FaceTime 的裝置的規格特性描述中有所記載,但它沒有暴露給第三方應用程式。預計這會在以後的 iOS 版本中有改變,但是可能僅限於新的裝置。

蘋果在 2013 年夏天釋出了一個 HEVC 開發的管理職位。

視訊工具箱

什麼時候需要直接訪問視訊工具箱?

蘋果的 SDK 提供了一個開箱即用的媒體播放器,它可以播放任何 QuickTime 相容的格式視訊。唯一不能播放的是在 iTunes 商店裡購買的受 FairPlay2 這個數字版權管理保護的內容。此外,蘋果的 SDK 包括對蘋果公司的可擴充套件的 HTTP 流媒體協議 HTTP Live Streaming (HLS) 的支援,這項協議被用在 iOS 以及 OS X 10.7 及以上的系統中。HLS 通常包括一小塊儲存為 MPEG-TS 格式 的 H.264/AAC 視訊,並且允許客戶端根據可用的硬體,在不同的版本之間動態切換。

如果你要在顯示在 iOS 或者 OSX 的內容上面覆蓋控制元件的話,你可以使用預設的播放框體。根據部署的裝置型號和作業系統版本,預設的播放器都可以正常執行,啟用硬體加速解碼,或者在發生錯誤時無縫地回滾到軟體解碼。這也適用於像 AVKit 和 AVFoundation 這樣的高層框架。當然,它們都是基於視訊工具箱的支援的,不過普通開發者並不需要知道這些。

然而除去 MP4 之外,還有更多的編碼格式,例如 MKV。也有 Adobe 和微軟開發的進一步可擴充套件的 HTTP 流媒體協議,比如 DASH 或者 Smooth 流媒體,它們也部署了一套類似的視訊編解碼器,但它們是不同的格式,從本質上來說是不同的協議。視訊工具箱支援自定義格式或協議是輕而易舉的事情。它接受原始的視訊流作為輸入,而且允許在裝置上對原始的或者已經編碼的視訊進行編碼。生成的結果儲存在檔案裡或者上傳到網路流中,以便隨後訪問和進一步處理。視訊工具箱是一種優雅的來達到原生解決方案效能的方式。而且它的用法在 WWDC 2014 Session #513, “Direct Access to Video Encoding and Decoding 有描述,還有很基本的程式碼

最後再補充一點 iOS 裝置上視訊工具箱開發的知識。它在 iOS 4 上作為一個私有的框架被引入,在最近的 iOS 8 開放給開發者。建立 target 低於 8.0 的專案時,匯入視訊工具箱不會有任何問題,因為實際的 API 大部分沒有改變。然而,任何新建會話的請求將會因為無文件的錯誤 -12913 被終止,因為出於安全考慮,這個框架不適用於舊版本 OS 的沙盒程式。

視訊工具箱用法的基本概念

視訊工具箱是一個基於 CoreMedia,CoreVideo,CoreFoundation 框架的 C 語言 API,並且基於三種可用型別的會話:壓縮,解壓縮,畫素移動。它從 CoreMedia 和 CoreVideo 框架衍生了一些不同的關於時間和幀管理的資料型別,例如 CMTime 或 CVPixelBuffer。

為了說明視訊工具箱的基本概念,以下段落將描述如何建立一個只包含必要的結構和型別的解壓會話。壓縮會話和解壓縮會話是非常相似的,而在實踐中,畫素的傳送會話應該是基本用不到的。

初始化解壓會話的時候,視訊工具箱需要知道以 CMVideoFormatDescriptionRef 結構體描述的輸入的格式,以及 —— 除非你想使用預設的無引數 —— 你通過 CFDictionary 指定的輸出格式。視訊格式的描述可以從 AVAssetTrack 例項來獲取或者如果你使用自定義分路器 (demuxer) 的話,可以通過 CMVideoFormatDescriptionCreate 手動建立。最後,解碼後的資料是通過非同步回撥機制提供的。回撥引用和視訊格式的描述在呼叫 VTDecompressionSessionCreate 時需要,而設定輸出格式是可選的。

什麼是視訊格式描述

它是一個描述編碼視訊的不透明結構體。它包含一個 四字元碼 (FourCC) 來描述所使用的編碼,視訊尺寸,以及一個被叫做extensions 的字典。這些是什麼? 在 OS X 上,硬體加速解碼是可選的,預設情況下禁用。要啟用它,必須將kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder 設定上,或者如果硬體加速播放不可用的話,再配合將 kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder 設定為 fail。在 iOS 上這些是沒有必要的,因為硬體加速解碼是唯一的可用選擇,此外,extensions 允許你轉發像是 MPEG-4 Part 2 或 H.264 這樣的先進視訊編解碼器所需要的後設資料 (即 kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms ESDS 或 avcC。)。此外,它可能包含後設資料來通過 CVPixelAspectRatio 鍵處理非方形畫素。

視訊輸出格式

which allows direct drawing of the decoded image in an OpenGL context without copying the data back and forth between the main bus and the GPU. This is sometimes referenced as a 0-copy pipeline, as no copy of the decoded image is created for drawing.

這是一個純 CFDictionary。解壓會話的結果是一個原始的,未壓縮的視訊影象。為了高效率的輸出,硬體解碼器輸出偏向於選擇本機的色度格式,也就是 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange。然而,有許多其他的視訊格式可以用,並且轉碼過程中有 GPU 參與,效率非常高。可以通過設定 kCVPixelBufferPixelFormatTypeKey 鍵來啟用,我們還需要通過kCVPixelBufferWidthKey 和 kCVPixelBufferHeightKey 來設定整數的輸出尺寸。有一個可選的鍵也值得一提,kCVPixelBufferOpenGLCompatibilityKey,它允許在 OpenGL 的上下文中直接繪製解碼後的影象,而不是從匯流排和 CPU 之間複製資料。這有時候被稱為零拷貝通道,因為在繪製過程中沒有解碼的影象被拷貝。

請記住, “memcpy 就是犯罪” – Mans Rullgard,2013 Linux 嵌入式會議, http://free-electrons.com/blog/elc-2013-videos/

資料回撥記錄

VTDecompressionOutputCallbackRecord 是一個簡單的結構體,它帶有一個指標 (decompressionOutputCallback),指向幀解壓完成後的回撥方法。你需要提供可以找到這個回撥方法的例項 (decompressionOutputRefCon)。VTDecompressionOutputCallback 回撥方法包括七個引數:

  • 回撥的引用
  • 幀的引用
  • 一個狀態標識 (包含未定義的程式碼)
  • 指示同步/非同步解碼,或者解碼器是否打算丟幀的標識
  • 實際影象的緩衝
  • 出現的時間戳
  • 出現的持續時間

所有解碼或者丟幀的時候都會呼叫這個回撥。因此,你的實現必須高度優化,嚴格控制任何拷貝。原因是解碼器會被阻塞直到回撥返回,這可能導致譯碼器堵塞和進一步的阻塞。此外,請注意解碼器總是會按解碼順序返回幀,而解碼順序並不一定就是播放順序。幀的重新排序是由開發者決定的。

解碼幀

一旦會話建立,把每一幀輸入解碼器就像在公園裡散步。這個過程就是用會話的引用和要解碼的取樣緩衝,來重複地呼叫VTDecompressionSessionDecodeFrame,另外還有可選的高階標識。取樣緩衝可以從 AVAssetReaderTrackOutput 中獲得,或者作為替換,可以使用 CMBlockBufferCreateWithMemoryBlockCMSampleTimingInfo 和 CMSampleBufferCreate,來連同時間資訊一起手動地從原始的記憶體塊中建立。

小結

在特殊配置下,視訊工具箱是一個底層的,高效率的方式來加速視訊處理程式。上層框架 AVFoundation 允許直接把支援的媒體檔案解壓並且顯示到螢幕上,或者直接壓縮到一個檔案。當需要支援自定義檔案格式,流媒體協議,或需要直接訪問編解碼器鏈的時候,視訊工具箱是首選的工具。缺點上來說,想要掌握這些缺少文件的 API 是需要對複雜的視訊技術有著高深的知識的。但無論如何,這都是實現更好的使用者體驗,更高的效率,以及延長電池壽命的必經之路。

參考

相關文章