(馬蜂窩技術公衆號原創內容,ID: mfwtech)api
熟悉馬蜂窩的朋友必定知道,點擊馬蜂窩 App 首頁的發佈按鈕,會發現發佈的內容已經被簡化成「圖文」或者「視頻」。數組
長期以來,遊記、問答、攻略等圖文形式的形態一直是馬蜂窩發展的優點所在。將短視頻提高至與圖文並列的位置,是由於對於今天的移動互聯網用戶來講,內容更真實直觀、信息密度更大、沉浸感更強的短視頻已經成爲剛需。爲了使旅遊用戶擁有更好的內容交互體驗,豐富和完整原有的內容生態體系,馬蜂窩加碼了對短視頻領域的佈局。性能優化
如今,天天都會有大量短視頻在馬蜂窩產生,覆蓋美食、探店、景點打卡、住宿體驗等多種當地玩樂場景。馬蜂窩但願平臺的短視頻內容除了「好看」以外,更要「好用」。這個「好用」不只僅是爲有需求的用戶提供好用的旅行信息,更是指經過技術讓用戶的短視頻創做更加簡單易行。app
爲此,咱們在馬蜂窩旅遊 App 的視頻編輯功能中提供了「自定義編輯」與「模板創做」兩種編輯模式,使用戶既能夠經過「模板」快速創做與模板視頻同款的炫酷視頻,也可以進入「自定義編輯」模式發揮本身的創意,生成個性化視頻。框架
本文將圍繞馬蜂窩旅遊 App iOS 端中的視頻編輯功能,和你們分享咱們團隊視頻編輯框架的設計及業務實踐。機器學習
如前言所述,咱們要作的是可以支持「自定義編輯」與「模板創做」兩種模式的視頻編輯功能。編輯器
圖1:產品示意圖ide
首先咱們梳理一下「自定義編輯」模式下,須要提供的功能:工具
視頻拼接:將多段視頻按順序拼接成一段視頻佈局
播放圖片:將多張圖片合成一段視頻
視頻裁剪:刪除視頻中某個時間段的內容
視頻變速:調整視頻的播放速度
背景音樂:添加背景音樂,能夠與視頻原音作混音
視頻倒播:視頻倒序播放
轉場過渡:拼接的兩段視頻切換時增長一些過渡效果
畫面編輯:畫面旋轉,畫布分區、設置背景色,增長濾鏡、貼紙、文字等附加信息
有了上述這些功能,即可以知足「自定義編輯」模式的需求,可以讓用戶經過咱們的視頻編輯功能完成本身的創做。可是爲了進一步下降視頻編輯功能的使用門檻,讓製做炫酷視頻變得簡單,咱們還須要支持「模板創做」模式。即爲用戶提供「模板視頻」,用戶只須要選擇視頻或者圖片,即可創做出與「模板視頻」有一樣編輯特效的同款視頻,實現「一鍵編輯」。
支持「模板創做」模式後,咱們視頻編輯功能最終的流程圖以下:
圖2:完整流程圖
如圖所示,在媒體文件以外,多了一個模板 A 的輸入,模板 A 描述了要對用戶選擇的媒體文件作哪些編輯。同時在編輯器的輸出中多了一個模板 B,模板 B 描述了用戶在完成編輯後,最終作了哪些編輯。其中模板 B 的輸出,爲咱們解決了「模板視頻」來源的問題,即「模板視頻」既能夠經過運營手段生產,也能夠將用戶經過「自定義編輯」模式創做的視頻做爲模板視頻,使其餘用戶瀏覽該用戶發佈的視頻時,能夠快速創做同款視頻。
經過上述需求分析的過程,能夠總結出咱們的視頻編輯功能主要支持兩個能力:
常規視頻編輯的能力
描述如何編輯的能力
這兩個能力的劃分,爲咱們接下來進行視頻編輯框架的設計提供了方向。
常規視頻編輯的能力是一個視頻編輯框架須要提供的基本能力,可以支撐業務上的「自定義編輯」模式。「描述如何編輯」的能力則是將常規視頻編輯能力進行抽象建模,描述「對視頻作哪些編輯」這件事,而後將這種描述模型轉化爲具體的視頻編輯功能,便可以支撐起業務上的「模板創做」模式。因此咱們的編輯框架能夠劃分爲兩個主要的模塊:
編輯模塊
描述模塊
在兩個模塊之間,還須要一個轉換模塊,完成視頻編輯模塊與描述模塊之間的雙向轉換。下圖爲咱們須要的視頻編輯框架示意圖:
圖3:視頻編輯框架示意圖
編輯模塊所須要的具體功能,能夠隨着業務上的需求不斷迭代添加,目前咱們要支持的功能如圖中所列。
描述模塊則須要一個描述模型,將媒體素材與各類編輯功能完整的描述出來。同時也須要將模型保存成文件,從而可以被傳輸分發,咱們稱之爲描述文件。
另外在描述文件的基礎上,「模板創做」模式中的「模板」還須要標題、封面圖等運營相關的信息。因此還須要提供一個運營加工的功能,可以讓運營同事將描述文件加工爲模板。
轉換模塊負責的則是將視頻編輯功能抽象爲描述文件、將描述文件解析爲具體的編輯功能的任務,保證抽象與解析的正確性相當重要。
視頻編輯模塊在不一樣的開發平臺上都有很好的實現方案,好比 iOS 原生提供的 AVFoundation,使用普遍的第三方開源庫 GPUImage,以及更加通用的 ffmpeg 等。具體的實現方案能夠結合業務場景與項目規劃進行選擇,咱們目前在 iOS 端採用的方案是蘋果原生的 AVFoundation。如何結合 AVFoundation 實現咱們的視頻編輯框架會在下文具體介紹。接下來咱們就來看下具體功能模塊的設計與實現。
首先咱們對「自定義編輯」模式下須要支持的具體功能進行分析,發現能夠以編輯的對象爲標準,將編輯功能劃分爲兩類:段落編輯、畫面編輯。
圖4:段落編輯
圖5:畫面編輯
有了編輯功能的劃分後,要描述「對視頻進行哪些編輯」,咱們還須要一個視頻編輯描述模型。定義以下幾個概念:
時間線:由時間點組成的單向遞增直線,起始點爲 0 點
軌道:以時間線爲座標系的容器,容器內存放的是每一個時間點須要的內容素材及「畫面編輯」功能
軌道類型列表:
其中「視頻」、「圖片」、「音頻」類型軌道,是提供畫面與聲音內容的軌道。其他幾個類型的軌道,則是用於描述具體作哪些畫面編輯功能的軌道。特效類型軌道中能夠指定若干畫面編輯效果,如旋轉、分區等。
結合編輯功能的劃分,咱們能夠看出段落編輯功能的編輯對象是軌道內的段落,畫面編輯功能的編輯對象是軌道內存放的內容素材。
有了時間線、軌道、段落三個概念以及段落編輯、畫面編輯兩個編輯行爲的劃分後,咱們在抽象層面描述視頻的編輯過程以下:
圖6:視頻編輯描述模型示意圖
如上圖所示,經過該模型,咱們已經可以完整的描述出「對視頻進行哪些編輯」:
創做一個時長 60 秒的視頻,內容素材有視頻,圖片,音樂,分別對應軌道 一、軌道 二、軌道 3,而且有轉場、濾鏡效果,由軌道 四、軌道 5 指定(其餘效果再也不單獨描述,以轉場、濾鏡效果爲參考)。
該視頻由軌道 1 的 [0-20] 段、軌道 2 的 [15-35] 段、軌道 1 的 [30-50] 段以及軌道 2 的 [45-60] 段拼接而成。
[0-60] 視頻全段有背景音樂,音樂由軌道 3 指定。
[15-20]、[30-35]、[45-50] 三段內有轉場效果,轉場效果由軌道 4 指定。
[15-35] 段有濾鏡效果,濾鏡效果由軌道 5 指定。
有了上述的視頻編輯描述模型後,咱們還須要具體的文件來存儲和分發該模型,即描述文件,咱們使用 JSON 文件來實現。同時還須要提供運營加工的能力,使運營同事爲描述文件添加一些運營信息,生成模板。
舉個🌰
舉個🌰
經過上述視頻編輯描述模型與描述文件及模板的定義,結合轉換器,咱們即可以在用戶使用「自定義」編輯功能的基礎上,生成一份描述文件來描述用戶最終對視頻進行的編輯行爲。反過來咱們也能夠經過解析描述文件,將用戶選擇的素材根據描述文件進行編輯,快速生成與描述文件中的編輯行爲「同款」的視頻。
AVFoundation 音視頻編輯分爲素材混合、音頻處理、視頻處理、導出視頻這四個流程。
(1)素材混合器 AVMutableComposition
AVMutableComposition 是一個或多個軌道(AVCompositionTrack)的集合,每一個軌道會根據時間線存儲源媒體的文件信息,好比音頻、視頻等。
每一個軌道由一系列軌道段(track segments)組成,每一個軌道段存儲源文件的一部分媒體數據,好比 URL、軌道 ID(track identifier)、時間映射(time mapping)等。
其中 URL 指定文件的源容器,軌道 ID 指定須要用到的源文件軌道,而時間映射指定的是源軌道的時間範圍,而且還指定其在合成軌道上的時間範圍。
圖7:AVMutableComposition合成新視頻的流程
(來源:蘋果官方開發者文檔)
(2) 音頻混合 AVMutableAudioMix
AVMutableAudioMix 能夠經過 AVMutableAudioMixInputParameters 指定任意軌道的任意時間段音量。
圖8:音頻混合示意圖
(來源:蘋果官方開發者文檔)
(3)視頻渲染 AVMutableVideoComposition
咱們還可使用 AVMutableVideoComposition 來直接處理 composition 中的視頻軌道。處理一個單獨的 video composition 時,你能夠指定它的渲染尺寸、縮放比例、幀率等參數並輸出最終的視頻文件。經過一些針對 video composition 的指令(AVMutableVideoCompositionInstruction 等),咱們能夠修改視頻的背景顏色、應用 layer instructions。
這些 layer instructions(AVMutableVideoCompositionLayerInstruction 等)能夠用來對 composition 中的視頻軌道實施圖形變換、添加圖形漸變、透明度變換、增長透明度漸變。此外,你還能經過設置 video composition 的 animationTool 屬性來應用 Core Animation Framework 框架中的動畫效果。
圖9:AVMutableVideoComposition 處理視頻
(來源:蘋果官方開發者文檔)
(4) 導出 AVAssetExportSession
導出的步驟比較簡單,只須要把上面幾步建立的處理對象賦值給導出類對象就能夠導出最終的產品。
圖10:導出流程
(來源:蘋果官方開發者文檔)
結合 AVFoundation 框架,咱們在視頻編輯模塊中分別實現了以下幾個角色:
在視頻類型的軌道中,擴展出圖片類型軌道,即經過空的視頻文件生成視頻軌道,將所選的圖片做爲幀圖提供給混合器。
附加軌道:AVFoundation 提供了 AVVideoCompositionCoreAnimationTool 這個工具,可以方便的將 CoreAnimation 框架內的內容應用到視頻幀圖上。因此添加文字的功能,咱們在預覽端經過 UIKit 建立了一系列預覽視圖,導出時轉換到該工具的 CALayer 上。
段落:軌道中的某個時間段,做爲段落編輯的對象。
指令:關聯到指定的視頻段落,進行圖片處理,繪製每一幀畫面。
一個指令能夠關聯多條視頻軌道,從這些視頻軌道的指定時間段內獲取幀圖,做爲畫面編輯的對象。
指令中畫面編輯的具體實現方案,採用 CoreImage 框架。CoreImage 自己提供了一些內置的圖片實時處理功能。CoreImage 不支持的特效,咱們經過自定義 CIKernel 的方式來實現。
音頻混音器:針對添加音樂的功能,咱們使用 AVMutableAudioMix 完成。
視頻混合器:咱們最終要獲得的視頻文件,通常包含一條視頻軌道、一條音頻軌道。混合器就是將咱們輸入的媒體資源轉換爲軌道,根據用戶的操做或者由描述模型轉換,對視頻進行段落編輯、組裝指令進行畫面編輯,對音頻軌道進行混音,結合 AVPlayerItem 與 AVExportSession,提供實時預覽與最終合成的功能。
有了上述幾個角色後,在 iOS 端的視頻編輯模塊實現示意圖以下:
圖11:視頻編輯模塊示意圖
如上圖所示,混合器中包含兩條視頻軌道與一條音頻軌道。通常來講輸入的視頻與圖片文件,都會生成一條對應的視頻軌道,理論上混合器中應該有多條視頻軌道。咱們圖中混合器只保持兩條視頻軌道與一條音頻軌道,首先是爲解決視頻解碼器數量限制的問題,後面會有具體描述。其次是爲了保證明現轉場過渡功能。
指令序列由若干在時間段上連續的指令組成,每一個指令由時間段、幀圖來源軌道、畫面編輯效果組成。視頻編輯功能中的段落編輯功能,即是對指令段的拼接;畫面編輯功能,即是每一個指令段對幀圖作的編輯處理。混合器提供的預覽功能,能夠將編輯改動實時展現給用戶。肯定了編輯效果後,經過混合器提供的合成功能,便完成了最終視頻文件的合成。
有了視頻編輯模塊的實現方案後,咱們已經可以支持「自定義編輯」模式。最後經過轉換器的鏈接,即可以將描述模型與編輯模塊整合在一塊兒,完成對「模板創做」模式的支持。這裏轉換器的實現較爲簡單,即將 JSON 格式描述文件解析爲數據模型,混合器根據用戶選擇的素材與描述模型建立本身內部的軌道模型,拼接指令段便可。
另外一方面,混合器在完成編輯導出時,將本身內部的軌道模型與指令信息組裝成數據模型,生成 JSON 格式的描述文件。
圖12:描述模型與編輯模塊相關轉換
在實現上述編輯框架的過程當中,咱們遇到過不少的問題,多數是因爲 AVFoundation 中錯誤信息不夠明確,定位問題比較耗時,總結起來大部分都是軌道時間軸對齊引發的問題。除時間軸對齊問題外,咱們在這裏總結幾個在實現時須要考慮到的問題,與你們分享一下,避免踩一樣的坑。
(1) 混合器軌道數量限制
圖13:轉換前的混合器結構圖
緣由:經查證後發現是蘋果設備對視頻播放解碼器的數量有限制,導出視頻時,每條視頻軌道會使用一個解碼器,這就致使導出時若是視頻軌道數量超出解碼器數量的限制,沒法導出。
解決方案:軌道模型轉換,將最初混合器中的多視軌結構轉換爲目前的雙視軌結構,這樣在導出時便不會超出解碼器數量限制。
(2) 性能優化:倒播功能實現方案
問題:最初的實現方案爲導出一個新的視頻文件,幀序列是原視頻文件中的倒序。若是原視頻文件很大,用戶只裁剪了一種的一段,對這一段進行倒播時,仍然會將原視頻文件進行倒序處理,導出一份新的視頻,是一個十分耗時的操做。
解決方案:根據時間點獲取視頻文件的對應幀,倒播時只是將正常時間點轉換爲倒播後的時間點便可,不操做視頻文件。相似於對數組的操做,只操做下標,而不直接改變數組的順序。
(3) 性能優化:減小內存使用率
問題:預覽時使用原圖尺寸,消耗內存嚴重,添加多個高清圖片後,預覽過程會出現內存告警。
解決方案:在不影響用戶體驗的狀況下,使用低分辨率的圖片進行預覽,導出時使用原圖。
目前這套視頻編輯框架在馬蜂窩旅遊 App iOS 端運做良好,可以支撐業務的不斷迭代,能夠快速擴展出更多的畫面編輯功能,固然也還有一些須要優化的細節有待完善。
近期咱們會結合機器學習與 AR 技術,探索一些有趣好玩的視頻編輯場景,爲用戶提供更加個性化的旅行記錄工具。
本文做者:李旭、趙成峯,馬蜂窩內容中心 iOS 研發工程師。