得物視頻編輯工具優化全指南
一、背景介紹
隨著4G網絡的推廣和網絡帶寬的提升,視頻成為互聯網用戶主要的消費載體,用戶通過短視頻來分享和瀏覽信息。由此視頻的編輯功能越來越重要、越來越普遍。視頻編輯的App也如雨后春筍般涌現。
為更好地推動得物App社區業務的發展,得物也自研符合得物需求的視頻編輯工具。我們致力于打造一個“更快、更強”的視頻編輯工具。
二、視頻編輯工具介紹
為了讓大家更好地了解得物App的視頻編輯工具,我們先簡單介紹一下視頻編輯工具的主要功能。
下面是得物App視頻編輯工具的主要功能:
視頻編輯工具的重點如下:
- 視頻編輯工具需要操作的資源:
文字:包括普通的文字、特殊的藝術字、花字等等;
圖片:包括靜態圖,如JPEG/PNG等等,也包括HEIC/GIF等動態圖;
視頻:包括各種各樣的視頻(各種編碼和封裝格式),主流的格式一般是MP4的封裝格式、H264視頻編碼格式、AAC音頻編碼格式等等;
音頻:包括各種各樣的音頻(各種編碼和封裝格式),當然視頻當然也是包含音頻軌道的。
- 視頻編輯工具主要的操作方式:
操作圖片、視頻幀:我們知道視頻是一幀一幀的圖片組成的,所以操作視頻幀和操作圖片是一樣的道理,我們通過添加一些特效在圖片和視頻幀上面,實現一些有趣的效果來吸引用戶。
操作音頻:主流的操作音頻方式如倍速、調整音量、變調等等,都是現今短視頻的主要玩法。
視頻編輯工具最終生成的是一個新的視頻,這個視頻將特定的資源應用一些特效生成一個新的視頻。
下面的流程圖可以很方便地讓大家了解視頻編輯的工作流程。為了方便,我們輸入一個視頻,加上一些特效,生成一個新的視頻。
從上面的流程可以看出來,原始視頻A.mp4經過解封裝分離出音頻軌道和視頻軌道,對它們解碼之后,對音頻數據應用音頻特效、對視頻幀數據應用視頻特效,然后編碼封裝合成一個新的視頻。當然解碼和編碼都是有一個隊列控制的,流程圖上標注了,沒有深入展開,大家了解即可。
經過上面的介紹,大家對視頻編輯工具有了大概得了解,其實衡量一個視頻編輯工具做得好不好,主要從下面這幾個方面著手:
- 內存占用情況
- 導出視頻的速度如何
- 導出視頻的清晰度如何
下面從這三方面詳細展開給大家闡述得物App的視頻編輯工具優化的心路歷程。
三、內存優化
性能是所有程序好不好的首要指標,一個工具即使功能再強大,但是一點就崩潰,或者用著用著內存暴漲、應用卡死,估計這個應用不能稱為一個優秀的應用,下面我們具體談一談視頻編輯工具的優化檢測方案。
優化內存從良好的編碼習慣開始,尤其對音視頻這種對內存需求非常高的應用而言。例如一個1080 * 1920的視頻,解碼出來原始數據一幀圖片大小也是1080 * 1920,占用內存是1080 * 1920 * (8 * 3 ) / 8 = 5.93 MB,一個視頻幀就占用這么大,1秒一般有30幀,那得占用177.9MB,如果不加控制,那不管多高性能的手機也經不住這樣的折騰。希望下面的內存檢測和優化方案可以給你帶來一些幫助。
3.1 合理設計隊列
上面我們在介紹視頻編輯流程的視頻談到了解碼隊列和編碼隊列的概念。其實隊列這個概念在音視頻中使用非常頻繁,正是因為內存的限制,所以才引入隊列這個控制方式。大家可能還有點懵,但是看完下面的流程圖,我相信你一定會豁然開朗。
我們僅選取解碼的部分來分析一下隊列的重要應用。
在視頻編輯工具中有幾個重要的隊列:
- 解碼過程中:
Video Packet Queue:視頻解碼之前Packet存放的隊列,一般建議的隊列大小是100
Audio Packet Queue:音頻解碼之前Packet存放的隊列,一般建議的隊列大小是150
Video Frame Queue:視頻解碼之后Frame存放的隊列,一般建議的隊列大小是3
Audio Frame Queue:音頻解碼之后Frame存放的隊列,一般建議的隊列大小是8
- 編碼過程中:
- Encode Video Packet Queue:視頻編碼之后Packet存放的隊列,一般建議的大小是100
- Encode Audio Packet Queue:音頻編碼之后的Packet存放的隊列,一般建議的大小是150
按照上面的方式設計隊列的大小,可以在保證功能正常的情況下最大程度的降低內存占用,提升用戶體驗。
3.2 排查內存泄漏
Android上排查內存泄漏的方式有很多,這里介紹兩種:
- Asan檢測
- Profile檢測
Asan全稱是AddressSanitizer是一種基于編譯器的快速檢測的工具,用于檢測原生代碼中的內存錯誤問題,Asan可以解決如下四種核心問題:
- 堆棧和堆緩沖區上溢、下溢
- 釋放之后堆重新使用問題
- 超過范圍的堆棧使用情況
- 重復釋放、錯誤釋放問題
Asan的使用方式建議參考google官方文檔,這兒就不多作介紹了:
https://github.com/google/sanitizers/wiki/AddressSanitizer
關于Profile的使用,如果需要檢測Native內存使用情況,需要滿足API>=29,大家在使用的時候需要非常注意。
下面是我們在demo中應用Asan抓取的堆棧:
顯示message是:heap-use-after-free on address 0x004ac1e41080 說明是使用了已經釋放掉的內存了,再繼續看,這個內存具體在什么地方被釋放的?0x004ac1e41080 is located 0 bytes inside of 1792-byte region [0x004ac1e41080,0x004ac1e41780) Asan一個很大的優勢就是可以追蹤內存釋放的路徑,防止出現內存泄漏和野指針問題,特別是野指針,一旦出現特別難排查,簡直是C++開發的噩夢,希望大家用好工具,同時培養良好的C++編碼習慣。
3.3 優化線程
另一個影響內存的重要因素是線程,視頻編輯工具涉及到的線程非常多,線程的使用得遵循一些基本的原則:
- 盡量少創建線程
- 盡量少使用pthread_mutex_t
- 本著功能隔絕原則使用線程
- 能同步就別異步
以編輯模塊為例,這兒列一下我們使用到的所有線程:
- GL處理線程
- 視頻解封裝線程
- 視頻中視頻軌道解碼線程
- 視頻音頻軌道解碼線程
- 抽取縮略圖線程
- 音頻編碼線程
- 視頻編碼線程
- 視頻封裝線程
如果插入了獨立的音頻文件,還需要添加兩個額外的線程:
- 音樂文件播放線程
- 音樂文件解碼線程
上面列出的是一個視頻編輯工具能正常工作所必備的最少線程,如果你的視頻編輯工具中多了什么線程,我們建議可以適當優化一下,畢竟少一個線程,可以少一分開銷,而且少一分線程同步的工作。
我們在底層也按照Android的消息機制重寫了一套C++層的消息分發SDK,這個我們后續會另外分享文章闡釋我們定制的消息分發SDK,這兒點到為止。
四、提升導出視頻的速度
我們使用視頻編輯工具,最終是希望導出一個視頻,如果這個導出的過程很慢,那肯定是無法忍受的,從上面的介紹我們已知視頻的導出需要經過“解碼——應用特效——編碼”的過程,其中解碼和編碼這兩個過程對速度的影響至關重要。因為解碼和編碼視頻需要耗費大量的資源,目前主要有兩種方式——“軟解/編碼”和“硬解/編碼”。
如果你使用過FFmpeg或者其他使用CPU進行視頻編解碼的來處理視頻的話,你可能已經遇到了處理速度慢的問題。這主要是因為軟編碼和軟解碼使用CPU進行運算,而CPU在處理視頻上的速度遠低于DSP芯片;簡而言之“軟解/編碼”主要通過CPU來工作,通過CPU來主導大量的計算工作,是原始的處理方式,當然耗費的時間也比較長;“硬解/編碼”是通過GPU來處理,GPU是專用的圖形處理芯片,對視頻的解碼和編碼有專門的優化,所以編碼和解碼的速度非??臁?/p>
Android上使用MediaCodec來實現“硬解/編碼”,iOS上使用VideoToolBox來實現“硬解/編碼”,這里著重介紹Android上編碼解碼的速度優化。
從上面的流程我們可以看出,編碼在解碼的后面,一個時長60s(30fps)的視頻,需要解碼1800幀,然后編碼1800幀視頻才能完整生成另外一個視頻,這樣串行的等待是耗時的主要原因。
這時候我們參考多線程方案,將一個60s的視頻均分為兩段,然后這兩段視頻同時進行解碼操作,生成導出了兩個30s的臨時緩存視頻文件,隨后將這兩個30s的視頻合并為一個60s的B.mp4視頻,最后刪除臨時緩存文件,這樣我們只需要同時處理900幀的數據,理論上可以提升一倍的導出速度。
這就是并行導出,下面是得物App并行導出的基本流程。
首先我們要明確導出視頻是需要消耗資源的,這個資源就是MediaCodec,最終是送入到GPU中處理,一個手機中的MediaCodec實例是有限的,正常情況下,一個手機可以提供的MediaCodec實例最多有16個,如果當前使用的MediaCodec實例超過16個,那么手機將無法正常工作。MediaCodec資源是手機中的所有App共同持有。所以并行分段的個數不是越多越好。
- 只有一段,需要兩個MediaCodec(一個用來解碼視頻,一個用來編碼視頻),注意:音頻的解碼和編碼可以不要用MediaCodec,畢竟音頻的耗時少多了,不是瓶頸。
- 分成兩段需要四個MediaCodec,分成三段需要六個MediaCodec,分成四段需要八個MediaCodec,以此類推。
下面是并行導出的測試結果:
兩段并行速度提升50% ~ 70%,內存增加20%, 三段并行速度提升60% ~ 90%,內存增加80%;并行超過三段的話就無法明顯提升速度了。我們比較建議并行兩段,在一些性能很好的機型上并行三段。
如果有些同學對視頻導出過程中文件操作還有疑問的,下面的示意圖可以比較清楚地看出并行導出操作本地文件的過程:
- 并行導出的過程中,生成了兩個臨時文件
- 并行導出完成后,這兩個臨時文件合并為一個新的文件,兩個臨時生成的文件被刪除了(節省用戶寶貴的存儲空間)
- 原始文件jeffmony_out.mp4并沒有被刪除/修改
Tips:目前我們在處理過程中生成的臨時文件和最終的適配文件都會保存在/sdcard/Pictures/duapp/Compile/下,而在處理完成后的臨時文件清理過程會觸發在某些機型上的保護機制,建議后續調整到App的私有目錄下。
下面是普通導出和并行導出的測試速度對比:可以明顯的看出,同樣的視頻(應用同樣的濾鏡),左邊的并行導出速度幾乎是右邊普通導出的兩倍??梢姴⑿袑С鰧σ曨l視頻導出速度的提升非常明顯。
當然還有其他的提升導出速度的建議,例如在視頻幀特效處理的過程中,我們建議:
- 盡量采用FBO/EBO/ABO方式處理texture
- 紋理如果過大要進行壓縮
- 嚴禁采用glFinish()
這些做法都是我們在視頻編輯開發過程中的切實經驗,希望能給大家帶來一些幫助。
五、提升導出視頻的清晰度
一個視頻編輯功能是否足夠優秀,其中的一個重要指標就是同等條件下導出的視頻是否足夠清楚,通常而言,衡量視頻是否清晰的有兩種方式:
- 主觀標準:找一些用戶觀看不同的視頻,根據用戶的觀感輸出視頻清晰度的對比結果,用戶一般根據色彩、畫面亮度、柔和度等來評估清晰度。
- 客觀標準:利用算法計算視頻畫面質量分,目前比較推薦Netflix推出的開源庫VMAF來計算視頻幀的質量分。
實際上主觀標準是比較準確的,但是可操作性比較差,特別是處理海量視頻的時候,需要大量的人力,無法有效開展,因此日常工作中還是推薦客觀標準進行海量計算,主觀標準進行重點判斷。具體的可以結合業務的重要程度來開展。
下面結合我們實際的工作給出具體提升視頻清晰度的方式:
- 視頻基礎編碼信息優化
Profile優化:Profile有三種Level,分別是Baseline、Main、High,其中Baseline Profile對應清晰度最低,Android 3.0之后的版本都支持的,Main Profile清晰度比Baseline Profile清晰度要好,但是從Android 7.0之后才支持,High Profile清晰度最高,也是從Android 7.0之后才支持。我們在設置Encoder Profile Level之前,需要判斷一下當前是否支持。
Bitrate碼率設置:視頻碼率是視頻數據傳輸時單位時間內傳送的數據位數。單位是kbps,望文生義,碼率越大,單位時間填充的數據就越多,視頻質量就越高。但碼率也不是設置的越大越好,超過必要限度,對視頻畫質的提升已不明顯,建議采用合適的factor來調整碼率。Bitrate = width * height * frameRate * factor,其中factor=0.15。
Bitrate Mode:有三種通過的編碼模式——VBR(可變碼率)、CBR(固定碼率)、ABR(平均碼率),其中ABR是最好的方式,可以兼顧質量和視頻大小。
B幀設置:視頻有I幀、P幀、B幀構成,其中I幀最大,P幀次之,B幀最小,我們在編碼時盡量多設置B幀(在合理的范圍內),并不會降低清晰度,但是可以大大降低視頻的大小,這樣我們就可以相應地調大碼率,最終實現了提升清晰度的目標。
HEVC編碼優化:使用HEVC編碼,可以保證在不增加文件大小的情況下,大大提升視頻的清晰度。在相同的圖像質量下,HEVC編碼的視頻比H.264編碼的視頻約減少40%
- 色彩調優
綜合調整亮度、對比度、色溫、飽和度、銳度等顏色參數,進而優化整體的視頻畫面,讓視頻畫面看上去“更清晰”。
- 超分算法:采用ESRGAN算法,利用機器學習的優勢對圖片和視頻進行去模糊、Resize、降噪、銳化等處理,重建圖片,實現對圖片的超分辨率處理。
特征提?。河嬎阍朦c
非線性映射:放大,模糊化噪點
圖像重建:差分,平滑過度,去噪
下面是使用超分算法處理前后的對比圖,可以很明顯地看出右邊的圖更加清晰,少了很多噪點、圖片更亮、過度更平滑。
如果大家想了解視頻清晰度優化的技術細節,可以參考得物技術公眾號上發表的文章--視頻清晰度優化指南
六、總結
本文開篇從介紹得物App的主要功能展開,提出了視頻編輯工具優化的三個維度:
- 優化內存占用
- 提升視頻導出速度
- 提升導出視頻的清晰度
其中在“提升視頻導出速度”時重點談到了“并行導出”的技術方案,從最終的結果來看,視頻導出速度的提升非常明顯,同時也非常清楚地解釋了“并行導出”過程中為什么生成臨時文件?為什么有必要在導出完成之后刪除臨時文件?盡力給用戶帶來較好的體驗。
最后在“提升導出視頻的清晰度”中重點提到的超分算法應用效果提升明顯,超分之后的視頻幀相比原幀圖更加清晰、噪點更少,而且細節部分更加真實。