tft每日頭條

 > 圖文

 > 直播畫面怎麼才能流暢不卡頓

直播畫面怎麼才能流暢不卡頓

圖文 更新时间:2024-08-15 03:13:26

希望本文可以帶給大家一個相對全局的視角看待卡頓問題,認識到卡頓是什麼、卡頓的成因、卡頓的分類、卡頓的優化和一些經驗積累,有的放矢地解決 App 流暢性問題。接下來會從以下五個方面進行講述:

✦什麼是卡頓

✦為什麼會發生卡頓

✦如何評價卡頓

✦如何優化卡頓

✦加入我們

1. 什麼是卡頓

卡頓,顧名思義就是用戶體感界面不流暢。我們知道手機的屏幕畫面是按照一定頻率來刷新的,理論上講,24 幀的畫面更新就能讓人眼感覺是連貫的。但是實際上,這個隻是針對普通的視頻而言。對于一些強交互或者較為敏感的場景來說,比如遊戲,起碼需要 60 幀,30 幀的遊戲會讓人感覺不适;位移或者大幅度動畫 30 幀會有明顯頓挫感;跟手動畫如果能到 90 幀甚至 120 幀,會讓人感覺十分細膩,這也是近來廠商主打高刷牌的原因。

對于用戶來說,從體感角度大緻可以将卡頓分為以下幾類:

直播畫面怎麼才能流暢不卡頓(一文讀懂直播卡頓優化那些事兒)1

這些體驗對于用戶可以說是非常糟糕的,甚至會引起感官的煩躁,進而導緻用戶不願意繼續停留在我們的 App。可以說,流暢的體驗對于用戶來說至關重要。

2. 為什麼會發生卡頓

用戶體感的卡頓問題原因很多,且常常是一個複合型的問題,為了聚焦,這裡暫隻考慮真正意義上的掉幀卡頓。

2.1 繞不開的 VSYNC

我們通常會說,屏幕的刷新率是 60 幀,需要在 16ms 内做完所有的操作才不會造成卡頓。但是這裡需要明确幾個基本問題:

  1. 為什麼是 16ms?
  2. 16ms 内都需要完成什麼?
  3. 系統如何盡力保證任務在 16ms 内完成?
  4. 16ms 内沒有完成,一定會造成卡頓嗎?

這裡先回答第一個問題:為什麼是 16ms。早期的 Android 是沒有 vsync 機制的,CPU 和 GPU 的配合也比較混亂,這也造成著名的 tearing 問題,即 CPU/GPU 直接更新正在顯示的屏幕 buffer 造成畫面撕裂。後續 Android 引入了雙緩沖機制,但是 buffer 的切換也需要一個比較合适的時機,也就是屏幕掃描完上一幀後的時機,這也就是引入 vsync 的原因。

早先一般的屏幕刷新率是 60FPS,所以每個 vsync 信号的間隔也是 16ms,不過随着技術的更疊以及廠商對于流暢性的追求,越來越多 90fps 和 120fps 的手機面世,相對應的間隔也就變成了 11ms 和 8ms。

那既然有了 VSYNC,誰在消費 VSYNC?其實 Android 的 VSYNC 消費者有兩個,也就對應兩類 VSYNC 信号,分别是 VSYNC-app 和 VSYNC-sf,所對應的也是上層 view 繪制和 surfaceFlinger 的合成,具體的我們接下來詳細說。

直播畫面怎麼才能流暢不卡頓(一文讀懂直播卡頓優化那些事兒)2

這裡還有一些比較有意思的點,有些廠商會有 vsync offset 的設計,App 和 sf 的 vsync 信号之間是有偏移量的,這也在一定程度上使得 App 和 sf 的協同效應更好。

2.2 View 颠沛流離的一生

在講下一 part 之前先引入一個話題:

一個 view 究竟是如何顯示在屏幕上的?

我們一般都比較了解 view 渲染的三大流程,但是 view 的渲染遠不止于此:

此處以一個通用的硬件加速流程來表征

直播畫面怎麼才能流暢不卡頓(一文讀懂直播卡頓優化那些事兒)3

  1. Vsync 調度:很多同學的一個認知誤區在于認為 vsync 是每 16ms 都會有的,但是其實 vsync 是需要調度的,沒有調度就不會有回調;
  2. 消息調度:主要是 doframe 的消息調度,如果消息被阻塞,會直接造成卡頓;
  3. input 處理:觸摸事件的處理;
  4. 動畫處理:animator 動畫執行和渲染;
  5. view 處理:主要是 view 相關的遍曆和三大流程;
  6. measure、layout、draw:view 三大流程的執行;
  7. DisplayList 更新:view 硬件加速後的 draw op;
  8. OpenGL 指令轉換:繪制指令轉換為 OpenGL 指令;
  9. 指令 buffer 交換:OpenGL 的指令交換到 GPU 内部執行;
  10. GPU 處理:GPU 對數據的處理過程;
  11. layer 合成:surface buffer 合成屏幕顯示 buffer 的流程;
  12. 光栅化:将矢量圖轉換為位圖;
  13. Display:顯示控制;
  14. buffer 切換:切換屏幕顯示的幀 buffer;

Google 将這個過程劃分為:其他時間/VSync 延遲、輸入處理、動畫、測量/布局、繪制、同步和上傳、命令問題、交換緩沖區。也就是我們常用的 GPU 嚴格模式,其實道理是一樣的。到這裡,我們也就回答出來了第二個問題:16ms 内都需要完成什麼

準确地說,這裡仍可以進一步細化:16ms 内完成 APP 側數據的生産;16ms 内完成 sf layer 的合成

直播畫面怎麼才能流暢不卡頓(一文讀懂直播卡頓優化那些事兒)4

View 的視覺效果正是通過這一整條複雜的鍊路一步步展示出來的,有了這個前提,那就可以得出一個結論:上述任意鍊路發生卡頓,均會造成卡頓

2.3 生産者和消費者

直播畫面怎麼才能流暢不卡頓(一文讀懂直播卡頓優化那些事兒)5

我們再回到 Vsync 的話題,消費 Vsync 的雙方分别是 App 和 sf,其中 App 代表的是生産者,sf 代表的是消費者,兩者交付的中間産物則是 surface buffer

再具體一點,生産者大緻可以分為兩類,一類是以 window 為代表的頁面,也就是我們平時所看到的 view 樹這一套;另一類是以視頻流為代表的可以直接和 surface 完成數據交換的來源,比如相機預覽等。

對于一般的生産者和消費者模式,我們知道會存在相互阻塞的問題。比如生産者速度快但是消費者速度慢,亦或是生産者速度慢消費者速度快,都會導緻整體速度慢且造成資源浪費。所以 Vsync 的協同以及雙緩沖甚至三緩沖的作用就體現出來了。

思考一個問題:是否緩沖的個數越多越好?過多的緩沖會造成什麼問題?答案是會造成另一個嚴重的問題:lag,響應延遲

這裡結合 view 的一生,我們可以把兩個流程合在一起,讓我們的視角再高一層:

直播畫面怎麼才能流暢不卡頓(一文讀懂直播卡頓優化那些事兒)6

2.4 機制上的保護

這裡我們來回答第三個問題,從系統的渲染架構上來說,機制上的保護主要有幾方面:

  1. Vsync 機制的協同;
  2. 多緩沖設計;
  3. surface 的提供;
  4. 同步屏障的保護;
  5. 硬件繪制的支持;
  6. 渲染線程的支持;
  7. GPU 合成加速;

這些機制上的保護在系統層面最大程度地保障了 App 體驗的流暢性,但是并不能幫我們徹底解決卡頓。為了提供更加流暢的體驗,一方面,我們可以加強系統的機制保護,比如 FWatchDog;另一方面,需要我們從 App 的角度入手,治理應用内的卡頓問題。

2.5 再看卡頓的成因

經過上面的讨論,我們得出一個卡頓分析的核心理論支撐:渲染機制中的任何流轉過程發生異常,均會造成卡頓

那麼接下來,我們逐個分析,看看都會有哪些原因可能造成卡頓。

2.5.1 渲染流程
  1. Vsync 調度:這個是起始點,但是調度的過程會經過線程切換以及一些委派的邏輯,有可能造成卡頓,但是一般可能性比較小,我們也基本無法介入;
  2. 消息調度:主要是 doframe Message 的調度,這就是一個普通的 Handler 調度,如果這個調度被其他的 Message 阻塞産生了時延,會直接導緻後續的所有流程不會被觸發。這裡直播建立了一個 FWtachDog 機制,可以通過優化消息調度達到插幀的效果,使得界面更加流暢;
  3. input 處理:input 是一次 Vsync 調度最先執行的邏輯,主要處理 input 事件。如果有大量的事件堆積或者在事件分發邏輯中加入大量耗時業務邏輯,會造成當前幀的時長被拉大,造成卡頓。抖音基礎技術同學也有嘗試過事件采樣的方案,減少 event 的處理,取得了不錯的效果;
  4. 動畫處理:主要是 animator 動畫的更新,同理,動畫數量過多,或者動畫的更新中有比較耗時的邏輯,也會造成當前幀的渲染卡頓。對動畫的降幀和降複雜度其實解決的就是這個問題;
  5. view 處理:主要是接下來的三大流程,過度繪制、頻繁刷新、複雜的視圖效果都是此處造成卡頓的主要原因。比如我們平時所說的降低頁面層級,主要解決的就是這個問題;
  6. measure/layout/draw:view 渲染的三大流程,因為涉及到遍曆和高頻執行,所以這裡涉及到的耗時問題均會被放大,比如我們會降不能在 draw 裡面調用耗時函數,不能 new 對象等等;
  7. DisplayList 的更新:這裡主要是 canvas 和 displaylist 的映射,一般不會存在卡頓問題,反而可能存在映射失敗導緻的顯示問題;
  8. OpenGL 指令轉換:這裡主要是将 canvas 的命令轉換為 OpenGL 的指令,一般不存在問題。不過這裡倒是有一個可以探索的點,會不會存在一類特殊的 canvas 指令,轉換後的 OpenGL 指令消耗比較大,進而導緻 GPU 的損耗?有了解的同學可以探讨一下;
  9. buffer 交換:這裡主要指 OpenGL 指令集交換給 GPU,這個一般和指令的複雜度有關。一個有意思的事兒是這裡一度被我們作為線上采集 GPU 指标的數據源,但是由于多緩沖的因素數據準确度不夠被放棄了;
  10. GPU 處理:顧名思義,這裡是 GPU 對數據的處理,耗時主要和任務量和紋理複雜度有關。這也就是我們降低 GPU 負載有助于降低卡頓的原因;
  11. layer 合成:這裡主要是 layer 的 compose 的工作,一般接觸不到。偶爾發現 sf 的 vsync 信号被 delay 的情況,造成 buffer 供應不及時,暫時還不清楚原因;
  12. 光栅化/Display:這裡暫時忽略,底層系統行為;
  13. Buffer 切換:主要是屏幕的顯示,這裡 buffer 的數量也會影響幀的整體延遲,不過是系統行為,不能幹預。
2.5.2 視頻流

除了上述的渲染流程引起的卡頓,還有一些其他的因素,典型的就是視頻流。

  1. 渲染卡頓:主要是 TextureView 渲染,textureview 跟随 window 共用一個 surface,每一幀均需要一起協同渲染并相互影響,UI 卡頓會造成視頻流卡頓,視頻流的卡頓有時候也會造成 UI 的卡頓;
  2. 解碼:解碼主要是将數據流解碼為 surface 可消費的 buffer 數據,是除了網絡外最重要的耗時點。現在我們一般都會采用硬解,比軟解的性能高很多。但是幀的複雜度、編碼算法的複雜度、分辨率等也會直接導緻解碼耗時被拉長;
  3. OpenGL 處理:有時會對解碼完成的數據做二次處理,這個如果比較耗時會直接導緻渲染卡頓;
  4. 網絡:這個就不再贅述了,包括 DNS 節點優選、cdn 服務、GOP 配置等;
  5. 推流異常:這個屬于數據源出了問題,這裡暫時以用戶側的視角為主,暫不讨論。

2.5.3 系統負載

  1. 内存:内存的吃緊會直接導緻 GC 的增加甚至 ANR,是造成卡頓的一個不可忽視的因素;
  2. CPU:CPU 對卡頓的影響主要在于線程調度慢、任務執行的慢和資源競争,比如降頻會直接導緻應用卡頓;
  3. GPU:GPU 的影響見渲染流程,但是其實還會間接影響到功耗和發熱;
  4. 功耗/發熱:功耗和發熱一般是不分家的,高功耗會引起高發熱,進而會引起系統保護,比如降頻、熱緩解等,間接的導緻卡頓。
2.6 卡頓的分類

我們此處再整體整理并歸類,為了更完備一些,這裡将推流也放了上來。在一定程度上,我們遇到的所有卡頓問題,均能在這裡找到理論依據,這也是指導我們優化卡頓問題的理論支撐。

直播畫面怎麼才能流暢不卡頓(一文讀懂直播卡頓優化那些事兒)7

3. 如何評價卡頓3.1 線上指标

指标

釋義

計算方式

數據來源

FPS

幀率

取 vsync 到來的時間為起點,doFrame 執行完成的事件為終點,作為每幀的渲染耗時,同時利用渲染耗時/刷新率可以得出每次渲染的丢幀數。平均 FPS = 一段時間内渲染幀的個數 * 60 / (渲染幀個數 丢幀個數)

vsync

stall_video_ui_rate

總卡頓率

(UI 卡頓時長 流卡頓時長) / 采集時長

vsync

stall_ui_rate

UI 卡頓率

【> 3 幀】UI 卡頓時長 / 采集時長

vsync

stall_video_rate

流卡頓率

流卡頓時長 / 采集時長

vsync

stall_ui_slight_rate

輕微卡頓率

【3 - 6】幀丢幀時長 / 采集時長

vsync

stall_ui_moderate_rate

中等卡頓率

【7 - 13】幀丢幀時長 / 采集時長

vsync

stall_ui_serious_rate

嚴重卡頓率

【> 14】幀丢幀時長 / 采集時長

vsync

3.2 線下指标

Diggo 是字節自研的一個開放的開發調試工具平台,是一個集「評價、分析、調試」為一體的,一站式工具平台。内置性能測評、界面分析、卡頓分析、内存分析、崩潰分析、即時調試等基礎分析能力,可為産品開發階段提供強大助力。

指标

釋義

計算方式

數據來源

FPS

時機渲染幀率

數據獲取時間周期内,實際渲染幀數/ 數據獲取間隔時間

SF & GFXInfo

RFPS

相對幀率

數據獲取時間周期内,(理論滿幀-實際掉幀數)/ 數據獲取間隔時間

GFXInfo

Stutter

卡頓率

卡頓比。當發生 jank 的幀的累計時長與區間時長的比值。

SF

Janky Count

普通卡頓次數

單幀繪制耗時大于 MOVIE_FRAME_TIME 時,計一次 janky。

SF

Big Janky Count

嚴重卡頓次數

單幀繪制耗時大于 3*MOVIE_FRAME_TIME 時,計一次 big janky。

SF

4. 如何優化卡頓4.1 常用的工具4.1.1 線上工具

名稱

釋義

正式包慢函數

相對于灰度包,過濾了比較多監控,對性能損耗比較小,但是需要手動打開,單點反饋中不能保留反饋現場

灰度包慢函數

灰度上全量打開,針對版本間的數據對比和新增卡頓問題解決比較有效

ANR

ANR 的及時響應和處理

4.1.2 線下工具

工具名

備注

Systrace

暫不贅述

perfetto

加強版 systrace,可定制,可以參考官方文檔

Rhea

最常用也是最好用的工具,方便發現下下問題和歸因,和 perfetto 一起使用絕配,感興趣的同學可以移步 github 搜索 btrace

profiler

Androidstudio 自帶工具,比較方便,但是數據準确度不高

sf / gfxinfo

主要用于腳本和工具

4.2 常用的思路

這裡主要針對 UI 卡頓和 UI/流相互影響打來的卡頓。

對于 UI 卡頓來說,我們手握卡頓優化的 8 闆大斧子,所向披靡:

  1. 下線代碼;
  2. 減少執行次數;
  3. 異步;
  4. 打散;
  5. 預熱;
  6. 複用;
  7. 方案優化;
  8. 硬件加速;

總體思路就是「能不幹就不幹、能少幹就少幹、能早點幹就早點兒幹、能晚點兒幹就晚點兒幹、能讓别人幹就讓别人幹、能幹完一次當 10 次就隻幹一次,實在不行,再考慮自己大幹一場」。

這裡例舉出一些常見的優化思路,注意這一定也不可能是全部,如果有其他好的優化思路,我們可以一起交流。

直播畫面怎麼才能流暢不卡頓(一文讀懂直播卡頓優化那些事兒)8

4.3 一些做過的事兒4.3.1 解決 UI 卡頓引起的流卡頓

直播對于 SurfaceView 的切換是一個長期的專項,分為多期逐步将 SurfaceView 在直播全量落地,場景覆蓋秀場直播、聊天室、遊戲直播、電商直播、媒體直播等,業務上對于滲透率和停留時長有比較顯著的收益,同時功耗的收益也很可觀。

這裡是一個權衡的問題,SurfaceView 的兼容性問題 pk 帶來的收益是否能打平,一般來說,越是複雜的業務場景,收益約大。

4.3.2 解決 message 調度

FWatchDog 是基于對 MessageQueue 的調度策略和同步屏障原理,以均幀耗時為阈值判定丢幀後主動在 MessageQueue 中插入同步屏障,保證渲染異步 message 和 doframe 的優先執行,達到一種渲染插幀的效果,同時具備 ANR 自動恢複同步屏障的能力,保障打散的有效。

所以 FWatchDog 和打散是好的搭檔,能産生 1 1 大于 2 的效果。

4.3.3 減少執行次數

一個典型的應用場景就是滑動場景的 GC 抑制,能夠顯著提高用戶上下滑的使用體驗。這個場景相信每個業務都會存在,特别是存在大量遍曆的邏輯,優化效果明顯。

4.3.4 代碼下線

一些老的框架、無用的邏輯以及存在性不高的代碼都可以下線,這裡基本業務強相關,就不舉具體的例子了。

4.3.5 解決耗時函數(打散/異步)

首先是打散,直播做了很多 task 的拆分以及打散,第一可以減輕當前渲染幀的耗時壓力,第二可以和 FWatchDog 結合達到插幀的效果。這裡其實還可以控制 task 的執行優先級,包括隊列的插隊等,總之 MessageQueue 的合理調度是很有必要的。

異步的使用也相對比較多,一個埋點日志的框架,以及一些 inflate 的加載等,都可以使用異步來解決卡頓問題。

4.3.6 預熱

直播提供了一個預熱框架,可以讓直播内部的一次性成本邏輯得到在宿主側執行的機會,同時提供完備的隊列優先級管理、同步異步管理和 task 生命周期管理,降低直播内部首次加載的卡頓問題。

4.3.7 硬件加速

拉高硬件的運行性能,比如 CPU 頻率、GPU 頻率、線程綁大核以及網絡相關的調優,從底層提高 App 的運行體驗。

5. 加入我們

直播客戶端技術團隊是一個集體驗優化、平台建設、跨端、端智能、穩定性為一體的綜合性團隊,團隊氛圍 nice,技術成長快,有充足的自由度發揮自己的特長,為億級 DAU 産品保駕護航,也面臨更加豐富多樣的挑戰,每一行代碼都會讓數億的用戶體驗變得更好!現誠邀各位英才加入,對這些方向感興趣的同學都可以來聊一聊,内推鍊接:「鍊接」

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved