播放內核的“瘦身”,你只需要這樣做

播放內核的“瘦身”,你只需要這樣做

作者 | 阿里文娛無線開發專家 城泉

播放内核的“瘦身”,你只需要这样做

概述

優酷播放內核是優酷自主開發的一個基於pipeline結構的SDK。它對上承接了優酷豐富靈活的業務邏輯,對下屏蔽了各端系統的差異,是一個高可靠、可擴展、跨平臺的優秀播放SDK。

但是,跨團隊協作及長時間的迭代,也使得當前播放內核顯得有些“臃腫”。佔用內存過高、使用線程太多等這些問題除了會影響用戶的體驗之外,也在一定程度上制約了一些業務的實現,例如針對短視頻的多實例方案。所以,急需對內核各模塊進行一次“輕量化”的改造。目標是:

1)更少的線程

2)更小的內存

3)更低的功耗

播放内核的“瘦身”,你只需要这样做

改造前的摸底

優酷播放內核實現了一套基於pipelie的框架,結構如下:

播放内核的“瘦身”,你只需要这样做

包含了接口層,處理命令和消息上報的engine,透傳消息的filter層,主體幹活的module層,數據下載模塊以及渲染和後處理模塊。

經過梳理跟測試,確認我們的播放內核使用的線程會比一些開源的播放內核(比如ijkplayer)多很多,內存使用量以及視頻耗電量等數據相比競品也處於劣勢。所以我們亟需對我們的播放內核進行一輪改造。

播放内核的“瘦身”,你只需要这样做

改造的詳細過程

我們改造的方向包含:線程、內存、功耗這三個方面。希望用最少的線程實現整個播放流程,用最小的內存使得播放依然流暢,佔用最少的cpu資源使得播放更持久。

採用的策略是做“加法”。根據播放流程,保留必要的線程,去除冗餘的線程,重用可複用的線程。然後review每一個保留下來的線程,測試使用內存及cpu佔用率是否符合預期,如果異常再進行逐一排查。

線程精簡

優化前內核使用的線程數有近30個,相比其他開源播放器多了很多。其中有些是必不可少,有些是可被其他線程複用,還有些是邏輯冗餘,可以直接去除。在梳理要留下哪些線程的時候,我們考慮了一個播放過程所需要的線程“最小集”,應該會包括如下一些線程模塊:

  • engine:用於接收接口命令,以及上報內核消息;

  • source:用於數據讀取並驅動pipeline數據向後流動;

  • decoder:音視頻各一個,用於音視頻數據解碼;

  • consumer:音視頻各一個,用於同步及渲染;

  • hal buffer:用於解複用及緩存狀態監控;

  • ykstream:用於控制下載模塊並和切片解析模塊交互;

  • render:用於渲染管理。

可以看到,播放流程必須用的線程其實就9個。而其他的線程除了預加載管理、播放質量監控以及字幕相關等在需要的時候會被啟用之外,其餘都可以去除。

精簡步驟如下:

1)去除多餘的filter線程

filter只有在創建module的時候用到,後面都是消息透傳,顯得有些多餘,所以可以直接去除。將創建module的邏輯移到engine的prepare流程,打通engine與module之間的消息通道,上面下達的命令以及下面上報的消息不再經過filter。

2)去除消息傳遞器和時鐘管理器

優化前消息上報通道比較混亂,有些直接上報給engine,有些上報給消息傳遞器進行一次中轉,然後再上報給engine。消息傳遞器這層邏輯有些多餘,所以去除了這個線程,所有消息上報都通過engine。

時鐘管理器作為同步時間來用,這個不需要線程,線程的存在是用作一個定時器。目前內核使用到定時器的就一兩個點,通過其他線程邏輯複用,去除了對定時器的依賴,這個線程也可以去除。

3)去除接口命令線程和消息上報線程

接口層加了一個線程中轉一個下發的命令,目的是為了接口超時的時候內核有forcestop的機制。在經過多輪優化後,內核觸發forcestop的情況大大減少,所以這個線程顯得有些多餘,就算還會出現卡住的情況,也會有anr來替代原先的crash,這個線程可以去除。

消息上報線程是為了內核層多實例上報消息加上的,實際上經過代碼複用,這個線程也不是必須的,可以去除。

4)去除解複用線程和二級緩存線程

內核獲取數據一直是邏輯最臃腫的地方,優化前有5個線程來實現這部分功能。優化後保留3個即可,解複用線程和二級緩存線程可以去除。

5)去除預加載管理器和字幕解碼模塊

預加載管理器不管有沒有開啟預加載都會運行,需要加上開關控制,只有在預加載開啟情況下才會運行。

字幕的實現主要是數據讀取、解析和render,其中不同於音視頻,文本信息在讀取後就可以直接去解析,所以字幕解碼模塊可以去除。

優化後,線程有9個必須的,加上播放質量監控,總共保留12個線程。沒有字幕的視頻只剩下10個。

內存裁剪

消耗內存地方主要有四處:緩存下載數據的buffer、pipe管線中的buffer、存msg信息的結構體、以及各class對象的內存。class對象除非不用,否則沒有太多裁剪的空間,所以內存裁剪就從緩存、pipe管線及信息存儲結構體三個角度去實行。

1)排查內存使用不符合預期的地方

掃描線程內存數據發現,讀buffer的線程內存消耗高出設置值很多。分析每個es sample的數據,發現除了數據部分之外,還存了一個codec的context,每個packet都要存一個。各packet的codec context都應該是一樣的,只需存一份即可。內核針對這部分不合理的邏輯進行了修復,內存使用降低了近1/3。

2)減少緩存buffer

緩存buffer相比競品設置的有些大,考慮到下載模塊也有一塊不小的buffer,所以內核的buffer可以裁剪,平衡卡頓數據,可將buffer設置在較低的水位。

3)減少pipe管線內存使用

pipe管線內存加上內核二級緩存使用量達到3.5M,source重構後去除了二級緩存,加上對pipe buffer pool的優化,這部分內存可減小到0.5M。

4)優化部分數據結構

比如存放信息的AMessage結構,每一個AMessage會消耗4k bytes。針對hls智能檔的場景,每一條記錄都會創建一個AMessage,所以的記錄加起來會超過6MB,這還不包括其他使用AMessage的地方。所以我們重寫一個功能類似的結構體進行替換,接口上與AMessage保持一致,減少了內部不必要的內存開消。

優化後,播放內核峰值內存已經降到原來的1/3,大大減少了單個實例使用的內存數。

功耗優化

功耗的主要影響因素有:cpu佔用率、網絡請求時長、屏幕及audio等設備的耗電。屏幕亮度音量等這些因素是固定的,所以降低功耗主要從cpu佔用率和網絡請求時長這兩個方面去考慮。

1)減少不必要的流程,裁剪多餘線程

這部分在線程裁剪中已經完成,這裡不再詳述。

2)控制網絡請求時長,避免過長的網絡連接

移動設備在請求網絡的時候,網絡設備wifi/4G會及時通電,這部分耗電很大。所以大塊的讀取一段數據然後wait要好過頻繁小段的請求數據。考慮卡頓等其他因素,內核默認設置在緩存消耗到低於2/3之後才重新啟動下載。

3)替換數據存儲結構,去除冗餘存取邏輯

排查發現,每次數據寫入buffer,cpu都會異常的繁忙,這與預期不符。review代碼找到異常點:我們存儲數據用的是vector數據結構,每次來數據都是push到front,當vector的size達到數萬的量級之後,這個push_front的操作會非常的消耗cpu。修改的辦法是將vector改成list,數據寫入到tail,從header讀取,該問題不再復現。

4)omx同步調用改成異步,減少解碼cpu耗時

android平臺上,硬解omx模塊默認用的是同步調用模式。android9.0以下native層只提供了這種模式,會循環的進行queue/dequeue操作,cpu消耗較大。android9.0及以上,native層提供了omx的異步調用模式,會只在queue/dequeue完畢之後callback調用解碼模塊幹活,所以cpu消耗比同步要小。如下圖所示,異步比同步要明顯稀疏一些。

播放内核的“瘦身”,你只需要这样做

5)減少倍速算法冗餘計算

review發現audioconsumer線程cpu消耗比audio decoder多很多,不符合預期,檢查發現當沒有開啟倍速情況下,也會走倍速相關的運算邏輯,導致cpu異常消耗,修復前後對比如下圖:

6)內核層實現彈幕邏輯

彈幕的實現原先是應用層通過view來實現,在彈幕數據多的情況下,非常影響功耗,甚至會出現彈幕模糊的情況。所以考慮將彈幕的實現移到內核層,由內核接收彈幕數據實現render。經過驗證,優化後彈幕的功耗降低了2/3.

優化後,播放運行時平均cpu佔用率已經低於7%(android中端機測試),1080p/90分鐘的視頻耗電量降到12%,相比優化前有了30%的提升。

播放内核的“瘦身”,你只需要这样做

小結

至此,播放內核相比優化前已經大大的“瘦身”了。瘦身後內核的代碼邏輯變得更加的清晰,數據傳遞也更加簡潔高效,這讓參與內核開發的同學可以更多的關注到自己的業務本身。內存使用量大幅降低,只從內存的角度講,優化前兩個實例的內核,現在可以創建6個,極大的拓寬了上層業務邏輯的邊界。功耗也變得更低,大大提升了用戶的播放體驗。

需要注意的是:我們的業務複雜多變,參與開發的團隊也有很多,版本迭代一段時間之後,難免會讓內核變得越來越臃腫。所以我們需要對每個正式的版本進行內存、功耗等多個緯度的監測,發現問題立即修改,這樣便不會將這些問題積累下去。內核也要定期進行小規模的重構,去除不合理的代碼,統一通用的邏輯處理單元,這樣才能讓高質量的內核持續保持下去。

☞美團十年,支撐全球最大規模外賣配送的一站式機器學習平臺是如何煉成的?

☞比爾·蓋茨退出微軟公司董事會;蘋果 WWDC、微軟 Build 大會均改為線上舉辦;Rust 1.42.0 發佈| 極客頭條

☞騰訊提結合ACNet進行細粒度分類,效果達到最新SOTA | CVPR 2020

☞我最喜歡的雲 IDE 推薦!

☞智能合約編寫之Solidity的高級特性

☞返鄂復工人員自述:回武漢上班,要先飛合肥,再由公司包車接回去


分享到:


相關文章: