WWDC18 — Measuring and Optimizing HLS Performance
感謝公司非 iOS 部門的成員來分享 ~ Keico Tu ~ , 她隸屬於 SMT Team (Streaming Media Technology), 小弟借花獻佛分享 Keico 的報告, 各項連結整理在最下方的 Reference. 個人覺得 Keico 以 Content Team 的角度來講解這篇Session 相當的清楚明瞭, hen 推薦大家中午買個便當看個她的報告影片, 比原文還淺顯易懂 :)
大綱
- 如何監測 Player 的表現與可測量的 QoS (Quality Of Service)
- 如何找出影響 Player QoS 的因素
在做 Streaming 服務, 應當盡量減低上圖的出現頻率, 但因為播放環境難以模擬真實狀況, 我們需要定義出幾項觀測的指標, 來讓產品未送到使用者端時, 就能檢驗數據來衡量播放品質.
如何監測 Player 的表現與可測量的QoS (Quality Of Service)
要定義怎樣的 Streaming Quality 算好的, 哪些算不好的, 這樣才能有個衡量指標來檢測修改程式後的結果是優還是劣. 在定義前, 先來介紹一個簡單的 HLS Streaming 的步驟(由左而右: Startup Time -> Playback at 2 Mbps -> 1 Mbps etc.)
如下圖
Startup Time : 使用者按下 Play 按鈕, 到第一張畫面出來的時間, 可利用AVPlayerItem -> accessLog() -> AVPlayerItemAccessLogEvent -> startupTime, 去印出所花的時間. 這段時間的動作包含的 Client 去解析 Master Playlist 與選擇要播放的 Media Playlist (又稱之為Variant Playlist), 選定之後, AVFoundation 會去看是否要處理 FairPlay (DRM).
Playback at 2Mbps -> 1Mbps : 剛開始 Segment 下載速度都優於播放影片Segment, 一切都很美好, 但在 Segment 5 時, 可能因為網路狀況不好, 切到1Mbps Media Playlist.
Stall Duration -> 1Mbps : 下載 Segment 速度已經比不上播放的速度, 進入所謂的Stall 階段(這時候畫面通常會呈現 Loading 狀態), 直到下載 Segment 達到播放影片的要求, 才能繼續播放.
透過上敘的步驟, 大致可歸類成五個 KPI (Key Performance Indicator), 如下圖
Startup Time / Stall Count (Buffering 出現幾次) / Stall duration (Buffering 多久) / indicated bitrate (一整個播放過程中的平均 Bitrate 為多少) / Error (AVPlayerItemErrorLog 出現多少次), 這幾項都是可以拿來衡量播放的品質到底好不好
如何找出影響Player QoS 的因素
To Reduce Startup Time (KKStream WWDC Report 9:30 ~ 17:00)
上圖為即將呈現第一張 Frame 給使用者看到的 Startup time
Step 1: 下載 m3u8 segment, 做 DRM protocol (FairPlay)
Step 2: 自動 Seek 到使用者上一次觀看的時間點, 導致 Buffering
Step 3: 選擇發音語系, 像是日語或者西班牙語
如何減少 Startup time ?
1. 透過此篇(AVContentKeySession Best Practices), 再進入 Player 頁面前就做完驗證 Key 的動作
2. 在 AVPlayer 執行 Play 之前, 就先把 Seek 與 設定語系做好, 避免 Rebuffering
3. 使用AVQueuePlayer幫助會自動播放下一集的功能(減低切換 Buffering)
Reducing Network Buffering Time Bitrate (KKStream WWDC Report 17:00 ~ 26:00)
Choice of variant: 最好的應對方式就是提供多組 Media Playlist 讓 Adaptive Streaming 可以因應環境變化選擇適合播放的 Media Playlist.
例如下圖
右半邊只提供一組 Media Playlist, 左半邊提供四組, 左半邊在網路狀況不佳的時候就能有較高的機率提供畫面給使用者觀看.
Content bitrate: 每部影片壓縮出來的 Bitrate 不盡相同, 而平常所稱某部影片為 3MB bitrate 或者 5MB bitrate 通常是指 Average bitrate, 如何針對不同影片壓出低 Bitrate 但維持高品質也是一門學問 (或許可以到這篇Streaming Meetup 2 許願能在 Streaming Meetup 3 有Bitrate Optimization Talk )
(●>ω<●)
Playlist target duration: 指的是 m3u8 segment duration 大小來作切換的單位, 業界通常以 5秒 ~ 10秒為主
Netwok bandwidth: 不是我們所能控制, 就不特別介紹
在 Reducing Network Buffering Time Bitrate 章節, 提供許多種狀況來介紹會 Buffering 的狀況, 在此就提及其中一項, 如下圖
藍色背景 10s 代表 Segement 的播放長度 (Target duration), 由此圖可知總共是 50s, 然後需要(12s + 10s + 8.5s + 6s + 9.6s = 46.1s) 下載時間, 而在第五個 10s 區間才可以開始播放的原因是 ”下載時間” 小於 “播放長度”, 也就是有長達 40s 等候時間(Buffering), 在此提出的解決方式是提供另一組 Media Playlist(720p), RESOLUTION=1280x720 來幫助第一個 Segment下載太慢時, 可在第二個 Segment 切換到 720p 的 Segement , 如下圖
在下載12s後, 系統判斷太慢進而切到更低的 Media Playlist(720p).
此外, 如果想要在一開始就播放順利, 可以設計怎麼選擇第一個 Media Playlist (通常選最低畫質, 但壞處就是品質差)
Playback Stall (KKStream WWDC Report 26:00 ~ End)
Playback Stall 指的是播一播影片停住的狀況. 可以透過兩個 Notification 可以知道什麼時候開始停住(AVPlayerItemPlaybackStalled), 什麼時候又開始播放(kCMTimebaseNotification_EffectiveRateChanged) , 如下圖
有很多情境會導致 Stall Duration 出現, 我們要怎麼去做 debug 的動作呢 ? 可以透過兩大神器 APIs : AVPlayerItemAccessLog, AVPlayerItemErrorLog, 如果debug 時, 這兩個 log 還找不出來問題點, 那你大概只能用想像力來找了😎
透過下圖來舉例怎麼看 Log 來推敲問題
在 AVPlayerItemErrorLogEvent 可發現 errorComment = Media file not received in 15s , 再搭配 AVPlayerItemAccessLog 可知道正在播放的Media Playlist bitrate 為 36 Mbps, 但當下的 bitrate 只到 2.8Mbps, 可推估出是不是網路不好, 可丟出警示框⚠️跟使用者提醒:
“⚠️ 如果想要播放 4K 影片, 請到網路品質佳的環境 ⚠️”
影片還有其他解決 Playback Stall 的問題, 可以看看 Keico 精湛的講解~
Debug with Content Team by Incoming Webhook from Slack
最後, 提供一個小撇步來幫助 Client Side 與 Content Team 一起 debug 的方式, 利用Slack Webhook 結合 AVPlayerItemErrorLogEvent 與 AVPlayerItemAccessLog 來幫助 debug.
Step 1 : Create Incoming Webhook , 拿到一組url 像是https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
Step 2 : 寫簡單的Post APIs
Step 3 : 送 Log 到 #kks_now_hiring 頻道
為什麼不直接看 print() 或者 NSLog() 呢, 因為有時候 Content Team 想要調整 Master / Media Playlist 的寫法, Client side 不用調整, 他們就可以直接看 #kks_now_hiring 頻道來 debug, 不需要接 Xcode 觀看 log, 且能把 Client 端的雜訊過濾掉, 專注於看 AVPlayerItemErrorLogEvent & AVPlayerItemAccessLog 的訊息.
大家有什麼方便的 debug 方式可以一起交流討論喔