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