WWDC 2022 音視訊相關 Session 概覽(EDR 相關)丨音視訊工程示例

語言: CN / TW / HK

這個公眾號會 路線圖式的遍歷分享音視訊技術 音視訊基礎(完成)  →  音視訊工具(完成)  →  音視訊工程示例(進行中)  →  音視訊工業實戰(準備) 關注一下成本不高,錯過乾貨損失不小 ↓↓↓

蘋果用 EDR 這個詞是為了跟 HDR 區分開,因為 HDR 在不同的場景可能對應著不同的理解:

  • HDR 顯示:更生動的顯示亮色和暗色

  • HDR 格式:HDR10、Dolby Vision

  • HDR 轉換函式:PQ、HLG

  • 色調對映(Tone Mapping):HDR → SDR

而 EDR(Extended Dynamic Range)是蘋果推出的一套渲染管線技術,以支援在不同的螢幕上同時正確顯示 SDR 和 HDR 內容。當顯示 HDR 的內容時,EDR 並不會直接將 HDR 區域變得更亮,而是識別到 HDR 內容後提高整體螢幕亮度的同時,降低非 HDR 區域的白點值,使得其看起來沒有那麼亮。

下圖展示了 EDR 在 Pro Display XDR 顯示器上的預設:

Pro Display XDR preset
Pro Display XDR preset

一般臺式電腦顯示器的持續亮度在 350 尼特左右,有些專業顯示器的會高一點,但大部分持續不了較長時間。Pro Display XDR 則可以達到 1000 尼特全屏持續亮度,峰值亮度達到 1600 尼特。這樣的效能,可以提供持續的高亮度。配合高效的背光控制,出色的明暗對比範圍從最亮的白一直跨越到最深的黑,可實現 1000000:1 對比度和格外逼真的 XDR 影像。

1、在 iOS 上探索 EDR

參見: Explore EDR on iOS [1]

這個 Session 的內容包含了下面幾點:

1)介紹了 EDR API 的新增特性

  • EDR API 開始支援 iOS 和 iPadOS。

  • 12.9 英寸 iPad Pro 新增兩個新特性:Reference 模式支援 EDR 渲染;Sidecar 支援 EDR 渲染(Sidecar 是蘋果的一項技術,支援將 iPad 作為 Mac 的擴充套件屏)。

其中,Reference 模式對 EDR 的支援如下:

  • 修正 SDR 峰值亮度為 100 nits;

  • 修正 HDR 峰值亮度為 1000 nits(這樣就留出了 10 倍(1000 nits / 100 nits)的 EDR headroom);

  • 支援關閉 HDR Tone Mapping;

  • 支援關閉環境光自適應(比如,iPhone 的 True Tone、Auto Brightness、Night Shift 等功能);

  • 支援白點和亮度的手動校準;

  • Reference 模式支援的最常見 5 種 HDR/SDR 視訊格式如下圖(不在下表中的格式,會使用預設模式):

Reference 模式支援的最常見 5 種 HDR/SDR 視訊格式

2)回顧了 EDR 的技術方案

如下圖所示,SDR 的畫素浮點數表示範圍為 ,其中 0.0 表示黑色,1.0 表示白色。在 EDR 的畫素浮點數表示中,SDR 的部分對映到 ,而大於 1.0 的部分就是比 SDR 更亮的 HDR 部分。

不像其他的 HDR 格式那樣,EDR 不會做 Tone Mapping 將畫素值都對映到 的範圍。這就意味著在渲染時,它有一套新的機制。

EDR Range

當渲染時,畫素浮點值範圍為 的 SDR 內容是始終會正常渲染的。 範圍的 HDR 內容也是可以渲染的。但是,超過了 EDR headroom 的部分就會被丟掉。

EDR Rendering

EDR headroom 的存在支援了亮度更高的 HDR 內容,但是它具體是多少呢?其實,EDR headroom 是動態的,它的值受到多種因素的影響,比如:裝置的顯示技術、當前的顯示亮度等等。

我們通常可以使用下面這個公式粗略估計 EDR headroom:

比如,上面提到的 Reference 模式下的 EDR headroom 就是 ,即 10 倍。

下表中列出了部分裝置的 EDR headroom:

一些裝置的 EDR headroom

3)EDR 內容的讀取

對於 HDR 圖片檔案的處理流程如下:

HDR 圖片檔案的渲染流程

示例程式碼如下:

HDR 圖片檔案的渲染示例程式碼
HDR 圖片檔案的渲染示例程式碼

4)使用 EDR

要使用 EDR 有下面幾個注意點:

  • 要使用
  • 設定 為 YES;
  • 內容支援 EDR:

    • 支援畫素緩衝區格式;

    • 支援轉換函式;

    • 使用擴充套件的顏色空間。

5)查詢 EDR headroom

EDR headroom 的資訊可以通過 NSScreen(macOS)或 UIScreen(iOS)來獲取。

比如,通過 UIScreen(iOS)可以獲取這些資訊:

  • 顏色的動態值:

    • 當前螢幕可能的最大值;

    • 當前的最大值;

  • Reference 模式的狀態;

  • Reference 模式狀態變化的通知。

示例程式碼如下:

查詢 EDR headroom
監聽 Reference 模式變化通知

通過查詢 EDR headroom 的資訊,可以用來做自定義的 Tone Mapping 演算法。

6)色調對映(Tone Mapping)

如果你不想去做自己的 Tone Mapping 演算法,而是想用 Apple 內建的演算法,需要用到這些能力:

  • CoreAnimation 庫提供了跟 EDR metadata 相關的介面;

  • 支援多種 metadata 引數設定,包括 HDR10 和 HLG 格式;

  • 注意,內建的 Tone Mapping 演算法不是全域性支援的,使用之前要檢查一下。

如下圖所示,在使用之前要檢查當前裝置是否可以支援 EDR metadata,然後去初始化對應格式的 EDR metadata,最後將其應用到 CAMetalLayer 來渲染時,就用使用系統自帶的 Tone Mapping 演算法了。

CAEDRMetadata 和 CAMetalLayer

下圖展示瞭如何初始化不同格式的 EDR Metadata:

初始化不同格式的 CAEDRMetadata

下圖展示了不同顏色空間格式建議的 EDR Metadata 的構造方法:

初始化不同格式的 CAEDRMetadata

2、基於 CoreImage、Metal、SwiftUI 展示 EDR 內容

參見: Display EDR content with Core Image, Metal, and SwiftUI [2]

在這個 Session 中,回顧了一下 EDR 相關的概念和術語,然後展示了一個基於 Core Image 來新增 EDR 支援的 Demo,最後提到了如何用 CIFilter 來建立支援 EDR 的影象去服務於相關內容的生產。

1)EDR 相關的概念和術語

EDR 相關的概念和術語,在前面的內容已經介紹過了,這裡就不再贅述了。

不過,這裡提到了可以獲取到 EDR 影象內容的幾種途徑,可以瞭解一下:

  • 使用 TIFF、OpenEXR 等支援浮點數儲存畫素值的影象格式來獲取 EDR 影象;

  • 通過 AVFoundation 從 HDR 的視訊中截幀獲得 EDR 影象;

  • 使用 Metal API 可以將 EDR 環境渲染到紋理上;

  • ProRAW、DNG 等儲存原始影象資訊的格式,可以用於渲染來還原 EDR 的高亮特性。

2)在 SwiftUI 應用中使用 CoreImage 和 Metal 併為其新增 EDR 支援

相關原始碼見: Generating an Animation with a Core Image Render Destination [3]

這個 Demo 中繪製了一幅動畫的 CIImage 並通過 Metal 來渲染它,這裡使用了 MTKView。

Animate a filtered image to a Metal view

大致流程如下圖所示,即 MetalView 呼叫其 來繪製,作為代理的 Renderer 在 方法中呼叫 ContentView 來提供影象去繪製:

MetalView、Renderer、ContentView

其中,最核心的程式碼分別是:

  • MetalView 的 方法:
MetalView makeView()
  • Renderer 的 方法:
Renderer draw()
Renderer draw()
  • ContentView 的 方法:
ContentView provider()

接下來,則是在這個流程中新增 EDR 支援,包括 3 個步驟:

  • 1、初始化 MetalView 時,為其新增 EDR 配置;

  • 2、每次渲染動作前,計算 EDR headroom;

  • 3、基於 EDR headroom 構造 CIImage。

對應的程式碼改動如下:

  • MetalView 的 方法中,當構建 MetalView 時,要設定對應 layer 的幾個屬性如下:
MetalView makeView() 改動
  • Renderer 的 方法中,每次渲染前需要獲取 EDR headroom,並傳給 provider:
Renderer draw() 改動
  • ContentView 的 方法中,要增加 headroom 引數,並使用這個 headroom 引數和 CIFilter 來一起構建 CIImage,這個 CIImage 就可以實現 EDR 渲染展示了:
ContentView provider() 改動

3)使用內建的 CIFilter 來支援 EDR

CoreImage 中有超過 150 款 內建的 CIFilter 支援 EDR。

CIFilters with EDR

在使用一款 CIFilter 時,要想知道它是否支援 EDR,可以用如下的程式碼來做一下檢查:

Check if a filter supports EDR

下面展示瞭如何基於 headroom 編寫一個可以生成高亮白色的 shading image,並結合一個 Ripple 效果的 CIFilter 來生成 EDR 的影象。

Ripple CIFilter supports EDR
Ripple CIFilter supports EDR

4)基於 CIColorCube filters 編寫自定義的 CIFilter 來支援 EDR

其中 CIColorCubeWithColorSpace 是一個比較受歡迎的用於 SDR 圖片的濾鏡。以前,在使用它時有一個嚴格的限制:輸入和輸出的 RGB 顏色值都在 0-1 的範圍內。當我們要支援 EDR 時,可以配置 CIColorCubeWithColorSpace 濾鏡的顏色空間為 EDR 格式的顏色空間,比如:HLG 或 PQ,這時候就可以突破 RGB 顏色值只在 0-1 範圍的限制了,從而生產出最佳效果的 EDR 的內容。但是,需要注意,對應的 cube data 需要在對應顏色空間的有效範圍內。同時,還可能需要增加 cube data 的維度。

有時候,你可能想要使用 SDR cube data 用於 EDR 影象,在最新的 API 中,可以設定 屬性為 來告訴 filter 來對 SDR cube data 進行推斷,這時候你就可以給一個 filter 輸入一個 EDR 影象,並從輸出獲得 EDR 影象。

SDR Cube Data for EDR Image

5)編寫自定義 CIKernel 的最佳實踐

以往對於 RGB 的值必須保持在 0-1 範圍內的限制可以去掉了,超過這個範圍,CIKernel 也可以正常工作。

CIKernel 最佳實踐:RGB 可以大於 1

但是,alpha 值仍然需要保持在 0-1 的範圍內。

CIKernel 最佳實踐:Alpha 必須小於 1

3、基於 AVFoundation、Metal 展示 HDR 視訊

參見: Display HDR video in EDR with AVFoundation and Metal [4]

這個 Session 中介紹瞭如何基於 AVFoundation 和 Metal 來構建高效的 EDR 渲染管線。其中,包括:

  • 介紹如何支援 EDR 視訊的播放。不僅是簡單的基於黑盒的 AVPlayer 來實現,會深入的介紹如何基於 AVFoundation 來解碼 HDR 視訊,並在自定義的 EDR layer/view 上渲染。

  • 介紹如何支援 EDR 視訊的後處理。基於 CoreVideo Display Link 實時訪問解碼後的的視訊幀並送給 CoreImage filter 或 Metal shader 來進行影象或特效處理,最後將處理後的視訊幀交給 Metal 來渲染。

HDR 視訊的播放
HDR 視訊後處理

整個 Session 的內容從下面幾個方面展開:

1)Apple EDR 視訊框架

Apple EDR 視訊框架如下圖所示:

Apple EDR 視訊框架

首先是 AVKit 框架,我們可以基於 AVKit 來建立支援視訊播放的使用者介面,完成傳輸控制、章節導航、畫中畫播放、字幕、隱藏式字幕顯示等功能,AVKit 可以將 HDR 內容在 EDR 管線中播放。這些都可以通過 AVPlayerViewController 來實現。不過,如果想要進一步處理視訊幀,那就要使用更底層的媒體框架來控制整個 pipeline。

接下來是 AVFoundation 框架,AVFoundation 是處理基於時間的音視訊媒體的全功能框架。使用 AVFoundation 可以輕鬆的播放、建立和編輯 QuickTime 電影和 MP4 檔案,播放 HLS 流,並在應用中構建強大的媒體功能。本次演講中會探索 AVPlayer 和相關 AVPlayerLayer 介面的使用。

Core Video 是一個為數字視訊提供管道模型的框架。它通過將流程劃分為離散的步驟來簡化處理視訊的方式。Core Video 還可以更輕鬆地訪問和操作單個幀,而不必擔心資料型別之間的轉換或顯示同步。我們將演示如何結合使用 DisplayLink、CVPixelBuffer、Core Image,以及如何配合使用 CVMetalTextureCache、Metal。

接著是 Video Toolbox 框架,這是一個底層框架,提供對硬體編碼器和解碼器的直接訪問。Video Toolbox 提供視訊壓縮和解壓縮服務,以及儲存在 Core Video 畫素緩衝區中的光柵影象格式之間的轉換。VTDecompressionSession 是一個強大的底層介面,本次不會討論,但高階開發人員可以進一步研究。

最後是 Core Media 框架,該框架定義了 AVFoundation 和其他高階媒體框架使用的媒體管道。可以使用 Core Media 的底層資料型別和介面來有效地處理媒體樣本、管理媒體資料佇列。

對於不同的應用場景,我們可以選擇不同的框架來實現:

  • 簡單的播放 HDR 視訊,可以使用 AVKit 和 AVFoundation;

  • 在指定的 layer 上播放 HDR 視訊,可以使用 AVPlayerLayer;

  • 對 HDR 視訊幀做後處理,可以使用 AVPlayer、CADisplayLink 將 CVPixelBuffer 傳送給 CoreImage 進行影象處理;

  • 對 HDR 視訊幀做後處理和渲染,可以使用 AVPlayer、CVMetalTextureCache 將 MetalTexture 傳送給 Metal 進行影象處理和渲染。

2)使用 AVKit 和 AVFoundation

如果需要簡單的播放 HDR 視訊媒體渲染到 EDR,可以使用 AVPlayerViewController 渲染 AVPlayer,也可以使用 AVPlayer 和 AVPlayerLayer 在 iOS 或 macOS 上播放自己的檢視。

AVPlayer 的用法

示例程式碼如下:

AVPlayerViewController 使用示例
AVPlayer+AVPlayerLayer 使用示例

如果需要實現實時視訊效果,比如:

  • 特效:

    • Color grading

    • Chroma keying

  • 影象處理:

    • CoreImage filters

    • Metal shaders

大致流程如下:

實時視訊效果

最終渲染一般都使用 CAMetalLayer,要支援正確的渲染 HDR 視訊,還需要為 CAMetalLayer 設定一些屬性:

CAMetalLayer 屬性設定

接下來,繼續展示如何結合 AVPlayer 和 CADisplayLink 來實時訪問解碼的視訊幀,大致流程如下:

AVPlayer+CADisplayLink 獲取視訊幀

下面是各個步驟對應的示例程式碼:

步驟 1
步驟 2
步驟 3
步驟 4

接下在 CADisplayLink 的回撥中,我們就可以從 AVPlayerItemVideoOutput 中來讀取 CVPixelBuffer 影象資訊進行後處理了。

一種方式是將 CVPixelBuffer 傳送到 Core Image 進行處理。Core Image 可以將一個或多個 CIFilter 串起來,為視訊幀提供 GPU 加速的影象處理。但是需要注意,並非所有的 CIFilter 都支援 EDR,可以通過 來遍歷支援 EDR 的濾鏡來使用。在下面的示例程式碼中,我們來新增一個簡單的濾鏡效果:

後處理

另一種方式是使用 Metal 和自定義的 Metal shader 來處理和渲染 CVPixelBuffer。我們來簡單介紹一下將 CVPixelBuffer 轉換為 Metal 紋理的過程:

  • 從 CVPixelBuffer 中獲取 IOSurface 物件;

  • 建立一個 MetalTextureDescriptor;

  • 把這個 MetalTextureDescriptor 作為引數,使用 從 MetalDevice 建立一個 MetalTexture。

這裡要小心可能存在紋理被重複使用和過度繪製的問題,所以要小心的加鎖;此外,並非所有的 PixelBuffer 格式都被 MetalTexture 支援,這也是為什麼我們在示例中用 half float 格式的原因。同時,實現這種轉換以保持最佳效能是一個深入的話題,這裡先不探討了。

正因為這些複雜性,我們才建議從 Core Video Metal 紋理快取中獲取 Metal 紋理,這是我們在下一節內容中要介紹的。

3)使用 CoreVideo 和 Metal

CVMetalTextureCache 是一種將 CVPixelBuffer 與 Metal 結合使用的簡單有效的方法。CVMetalTextureCache 很方便,可以直接從快取中獲取 Metal 紋理,無需進一步轉換。CVMetalTextureCache 自動橋接 CVPixelBuffer 和 MetalTexture,從而既簡化了程式碼,又保持了高效。通過保持 MTLTexture 到 IOSurface 的對映,CVMetalTextureCache 與 CVPixelBufferPools 配合使用還提供了效能優勢。最後,使用 CVMetalTextureCache 消除了手動跟蹤 IOSurfaces 的需要。下面的示例將展示如何使用 CVMetalTextureCache 從 Core Video 中直接提取 Metal 紋理,大致流程如下圖所示:

CVMetalTextureCache 從 CoreVideo 提取 Metal 紋理

下面是各個步驟對應的示例程式碼:

步驟 1、2
步驟 3、4

注意,在用 Objective-C 時需要保證在釋放 CVMetalTextureRef 之前要完成對 Metal 紋理的使用,可以藉助 Metal 命令緩衝區的 completion 回撥來實現。

參考資料

[1]

Explore EDR on iOS: https://developer.apple.com/videos/play/wwdc2022/10113/

[2]

Display EDR content with Core Image, Metal, and SwiftUI: https://developer.apple.com/videos/play/wwdc2022/10114

[3]

Animation with a Core Image Render: https://developer.apple.com/documentation/coreimage/generating_an_animation_with_a_core_image_render_destination

[4]

Display HDR video in EDR with AVFoundation and Metal: https://developer.apple.com/videos/play/wwdc2022/110565/

- 完 -

推薦閱讀
《WWDC 2022 音視訊相關 Session 概覽(HLS 相關)》
《iOS 視訊處理框架及重點 API 合集》
《iOS 音訊處理框架及重點 API 合集》
加我微信,拉你入群

謝謝看完全文,也點一下『贊』和 『在看』吧 ↓