馬蜂窩影片編輯框架設計及在 iOS 端的業務實踐
- 2019 年 10 月 3 日
- 筆記
(馬蜂窩技術公眾號原創內容,ID: mfwtech)
熟悉馬蜂窩的朋友一定知道,點擊馬蜂窩 App 首頁的發布按鈕,會發現發布的內容已經被簡化成「圖文」或者「影片」。
長期以來,遊記、問答、攻略等圖文形式的形態一直是馬蜂窩發展的優勢所在。將短影片提升至與圖文並列的位置,是因為對於今天的移動互聯網用戶來說,內容更真實直觀、資訊密度更大、沉浸感更強的短影片已經成為剛需。為了使旅遊用戶擁有更好的內容交互體驗,豐富和完整原有的內容生態體系,馬蜂窩加碼了對短影片領域的布局。
現在,每天都會有大量短影片在馬蜂窩產生,覆蓋美食、探店、景點打卡、住宿體驗等多種當地玩樂場景。馬蜂窩希望平台的短影片內容除了「好看」之外,更要「好用」。這個「好用」不僅僅是為有需求的用戶提供好用的旅行資訊,更是指通過技術讓用戶的短影片創作更加簡單易行。
為此,我們在馬蜂窩旅遊 App 的影片編輯功能中提供了「自定義編輯」與「模板創作」兩種編輯模式,使用戶既可以通過「模板」快速創作與模板影片同款的炫酷影片,也能夠進入「自定義編輯」模式發揮自己的創意,生成個性化影片。
本文將圍繞馬蜂窩旅遊 App iOS 端中的影片編輯功能,和大家分享我們團隊影片編輯框架的設計及業務實踐。
Part.1 需求分析
如前言所述,我們要做的是能夠支援「自定義編輯」與「模板創作」兩種模式的影片編輯功能。
圖1:產品示意圖
首先我們梳理一下「自定義編輯」模式下,需要提供的功能:
-
影片拼接:將多段影片按順序拼接成一段影片
-
播放圖片:將多張圖片合成一段影片
-
影片裁剪:刪除影片中某個時間段的內容
-
影片變速:調整影片的播放速度
-
背景音樂:添加背景音樂,可以與影片原音做混音
-
影片倒播:影片倒序播放
-
轉場過渡:拼接的兩段影片切換時增加一些過渡效果
-
畫面編輯:畫面旋轉,畫布分區、設置背景色,增加濾鏡、貼紙、文字等附加資訊
有了上述這些功能,便可以滿足「自定義編輯」模式的需求,能夠讓用戶通過我們的影片編輯功能完成自己的創作。但是為了進一步降低影片編輯功能的使用門檻,讓製作炫酷影片變得簡單,我們還需要支援「模板創作」模式。即為用戶提供「模板影片」,用戶只需要選擇影片或者圖片,便可創作出與「模板影片」有同樣編輯特效的同款影片,實現「一鍵編輯」。
支援「模板創作」模式後,我們影片編輯功能最終的流程圖如下:
圖2:完整流程圖
如圖所示,在媒體文件之外,多了一個模板 A 的輸入,模板 A 描述了要對用戶選擇的媒體文件做哪些編輯。同時在編輯器的輸出中多了一個模板 B,模板 B 描述了用戶在完成編輯後,最終做了哪些編輯。其中模板 B 的輸出,為我們解決了「模板影片」來源的問題,即「模板影片」既可以通過運營手段生產,也可以將用戶通過「自定義編輯」模式創作的影片作為模板影片,使其他用戶瀏覽該用戶發布的影片時,可以快速創作同款影片。
通過上述需求分析的過程,可以總結出我們的影片編輯功能主要支援兩個能力:
-
常規影片編輯的能力
-
描述如何編輯的能力
這兩個能力的劃分,為我們接下來進行影片編輯框架的設計提供了方向。
Part.2 框架設計
常規影片編輯的能力是一個影片編輯框架需要提供的基本能力,能夠支撐業務上的「自定義編輯」模式。「描述如何編輯」的能力則是將常規影片編輯能力進行抽象建模,描述「對影片做哪些編輯」這件事,然後將這種描述模型轉化為具體的影片編輯功能,便能夠支撐起業務上的「模板創作」模式。所以我們的編輯框架可以劃分為兩個主要的模組:
-
編輯模組
-
描述模組
在兩個模組之間,還需要一個轉換模組,完成影片編輯模組與描述模組之間的雙向轉換。下圖為我們需要的影片編輯框架示意圖:
圖3:影片編輯框架示意圖
-
編輯模組所需要的具體功能,可以隨著業務上的需求不斷迭代添加,目前我們要支援的功能如圖中所列。
-
描述模組則需要一個描述模型,將媒體素材與各種編輯功能完整的描述出來。同時也需要將模型保存成文件,從而能夠被傳輸分發,我們稱之為描述文件。
-
另外在描述文件的基礎上,「模板創作」模式中的「模板」還需要標題、封面圖等運營相關的資訊。所以還需要提供一個運營加工的功能,能夠讓運營同事將描述文件加工為模板。
-
轉換模組負責的則是將影片編輯功能抽象為描述文件、將描述文件解析為具體的編輯功能的任務,保證抽象與解析的正確性至關重要。
影片編輯模組在不同的開發平台上都有很好的實現方案,比如 iOS 原生提供的 AVFoundation,使用廣泛的第三方開源庫 GPUImage,以及更加通用的 ffmpeg 等。具體的實現方案可以結合業務場景與項目規划進行選擇,我們目前在 iOS 端採用的方案是蘋果原生的 AVFoundation。如何結合 AVFoundation 實現我們的影片編輯框架會在下文具體介紹。接下來我們就來看下具體功能模組的設計與實現。
Part.3 模組功能與實現
3.1 描述模組
3.1.1 功能劃分
首先我們對「自定義編輯」模式下需要支援的具體功能進行分析,發現可以以編輯的對象為標準,將編輯功能劃分為兩類:段落編輯、畫面編輯。
- 段落編輯:將影片段看作編輯對象,不關心畫面內容,只在影片段層面上進行編輯,包含如下功能:
圖4:段落編輯
- 畫面編輯:將畫面內容作為編輯對象,包含如下功能:
圖5:畫面編輯
3.1.2 影片編輯描述模型
有了編輯功能的劃分後,要描述「對影片進行哪些編輯」,我們還需要一個影片編輯描述模型。定義如下幾個概念:
-
時間線:由時間點組成的單向遞增直線,起始點為 0 點
-
軌道:以時間線為坐標系的容器,容器記憶體放的是每個時間點需要的內容素材及「畫面編輯」功能
- 軌道具有類型,一條軌道僅支援一種類型
- 段落:軌道中的一段,即軌道所屬時間線上兩個時間點及兩點之間的部分
- 段落也具有類型,與其所屬軌道類型保持一致
軌道類型列表:
其中「影片」、「圖片」、「音頻」類型軌道,是提供畫面與聲音內容的軌道。其餘幾個類型的軌道,則是用於描述具體做哪些畫面編輯功能的軌道。特效類型軌道中可以指定若干畫面編輯效果,如旋轉、分區等。
結合編輯功能的劃分,我們可以看出段落編輯功能的編輯對象是軌道內的段落,畫面編輯功能的編輯對象是軌道記憶體放的內容素材。
有了時間線、軌道、段落三個概念以及段落編輯、畫面編輯兩個編輯行為的劃分後,我們在抽象層面描述影片的編輯過程如下:
圖6:影片編輯描述模型示意圖
如上圖所示,通過該模型,我們已經能夠完整的描述出「對影片進行哪些編輯」:
-
創作一個時長 60 秒的影片,內容素材有影片,圖片,音樂,分別對應軌道 1、軌道 2、軌道 3,並且有轉場、濾鏡效果,由軌道 4、軌道 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 指定。
3.1.3 描述文件與模板
有了上述的影片編輯描述模型後,我們還需要具體的文件來存儲和分發該模型,即描述文件,我們使用 JSON 文件來實現。同時還需要提供運營加工的能力,使運營同事為描述文件添加一些運營資訊,生成模板。
- 描述文件: 根據影片編輯模型生成一份 JSON 文件
舉個?
- 模板: 由描述文件+若干業務資訊組成的JSON文件
舉個?
通過上述影片編輯描述模型與描述文件及模板的定義,結合轉換器,我們便可以在用戶使用「自定義」編輯功能的基礎上,生成一份描述文件來描述用戶最終對影片進行的編輯行為。反過來我們也可以通過解析描述文件,將用戶選擇的素材根據描述文件進行編輯,快速生成與描述文件中的編輯行為「同款」的影片。
3.2 編輯模組
3.2.1 AVFoundation 介紹
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:導出流程
(來源:蘋果官方開發者文檔)
3.2.2 編輯模組的實現
結合 AVFoundation 框架,我們在影片編輯模組中分別實現了如下幾個角色:
- 軌道:有影片與音頻兩種類型,存放幀圖與聲音。
-
在影片類型的軌道中,擴展出圖片類型軌道,即通過空的影片文件生成影片軌道,將所選的圖片作為幀圖提供給混合器。
-
附加軌道:AVFoundation 提供了 AVVideoCompositionCoreAnimationTool 這個工具,能夠方便的將 CoreAnimation 框架內的內容應用到影片幀圖上。所以添加文字的功能,我們在預覽端通過 UIKit 創建了一系列預覽視圖,導出時轉換到該工具的 CALayer 上。
-
段落:軌道中的某個時間段,作為段落編輯的對象。
-
指令:關聯到指定的影片段落,進行圖片處理,繪製每一幀畫面。
-
一個指令可以關聯多條影片軌道,從這些影片軌道的指定時間段內獲取幀圖,作為畫面編輯的對象。
-
指令中畫面編輯的具體實現方案,採用 CoreImage 框架。CoreImage 本身提供了一些內置的圖片實時處理功能。CoreImage 不支援的特效,我們通過自定義 CIKernel 的方式來實現。
-
音頻混音器:針對添加音樂的功能,我們使用 AVMutableAudioMix 完成。
-
影片混合器:我們最終要得到的影片文件,一般包含一條影片軌道、一條音頻軌道。混合器就是將我們輸入的媒體資源轉換為軌道,根據用戶的操作或者由描述模型轉換,對影片進行段落編輯、組裝指令進行畫面編輯,對音頻軌道進行混音,結合 AVPlayerItem 與 AVExportSession,提供實時預覽與最終合成的功能。
有了上述幾個角色後,在 iOS 端的影片編輯模組實現示意圖如下:
圖11:影片編輯模組示意圖
如上圖所示,混合器中包含兩條影片軌道與一條音頻軌道。一般來說輸入的影片與圖片文件,都會生成一條對應的影片軌道,理論上混合器中應該有多條影片軌道。我們圖中混合器只保持兩條影片軌道與一條音頻軌道,首先是為解決影片解碼器數量限制的問題,後面會有具體描述。其次是為了保證實現轉場過渡功能。
指令序列由若干在時間段上連續的指令組成,每個指令由時間段、幀圖來源軌道、畫面編輯效果組成。影片編輯功能中的段落編輯功能,便是對指令段的拼接;畫面編輯功能,便是每個指令段對幀圖做的編輯處理。混合器提供的預覽功能,可以將編輯改動實時展示給用戶。確定了編輯效果後,通過混合器提供的合成功能,便完成了最終影片文件的合成。
3.2.3 轉換器
有了影片編輯模組的實現方案後,我們已經能夠支援「自定義編輯」模式。最後通過轉換器的連接,便可以將描述模型與編輯模組整合在一起,完成對「模板創作」模式的支援。這裡轉換器的實現較為簡單,即將 JSON 格式描述文件解析為數據模型,混合器根據用戶選擇的素材與描述模型創建自己內部的軌道模型,拼接指令段即可。
另一方面,混合器在完成編輯導出時,將自己內部的軌道模型與指令資訊組裝成數據模型,生成 JSON 格式的描述文件。
圖12:描述模型與編輯模組相關轉換
Part.4 近期優化方向
4.1 踩過的坑
在實現上述編輯框架的過程中,我們遇到過很多的問題,多數是由於 AVFoundation 中錯誤資訊不夠明確,定位問題比較耗時,總結起來大部分都是軌道時間軸對齊引起的問題。除時間軸對齊問題外,我們在這裡總結幾個在實現時需要考慮到的問題,與大家分享一下,避免踩同樣的坑。
(1) 混合器軌道數量限制
- 問題:AVMutableComposition 可以同時添加很多的軌道,即一個 composition 內可以同時存在多條影片軌道,並且可以正常通過 AVPlayer 預覽播放。所以我們最初實現的編輯模組,混合器中支援多條影片軌道,如下圖所示。這種多條軌道結構,預覽時沒有問題,導出時卻出現了「無法解碼」的報錯。轉換前的混合器結構圖:
圖13:轉換前的混合器結構圖
-
原因:經查證後發現是蘋果設備對影片播放解碼器的數量有限制,導出影片時,每條影片軌道會使用一個解碼器,這就導致導出時如果影片軌道數量超出解碼器數量的限制,無法導出。
-
解決方案:軌道模型轉換,將最初混合器中的多視軌結構轉換為目前的雙視軌結構,這樣在導出時便不會超出解碼器數量限制。
(2) 性能優化:倒播功能實現方案
-
問題:最初的實現方案為導出一個新的影片文件,幀序列是原影片文件中的倒序。如果原影片文件很大,用戶只裁剪了一種的一段,對這一段進行倒播時,仍然會將原影片文件進行倒序處理,導出一份新的影片,是一個十分耗時的操作。
-
解決方案:根據時間點獲取影片文件的對應幀,倒播時只是將正常時間點轉換為倒播後的時間點即可,不操作影片文件。類似於對數組的操作,只操作下標,而不直接改變數組的順序。
(3) 性能優化:減少記憶體使用率
-
問題:預覽時使用原圖尺寸,消耗記憶體嚴重,添加多個高清圖片後,預覽過程會出現記憶體告警。
-
解決方案:在不影響用戶體驗的情況下,使用低解析度的圖片進行預覽,導出時使用原圖。
4.2 近期規劃
目前這套影片編輯框架在馬蜂窩旅遊 App iOS 端運作良好,能夠支撐業務的不斷迭代,可以快速擴展出更多的畫面編輯功能,當然也還有一些需要優化的細節有待完善。
近期我們會結合機器學習與 AR 技術,探索一些有趣好玩的影片編輯場景,為用戶提供更加個性化的旅行記錄工具。
本文作者:李旭、趙成峰,馬蜂窩內容中心 iOS 研發工程師。