(十九)深入了解 AVFoundation-編輯:使用 AVMutableVideoComposition 實現視頻加水印與圖層合成(上)——理論篇

一、引言

在短視頻、Vlog、剪輯工具日益流行的今天,給視頻添加 Logo、水印、時間戳或動態貼紙,已經成為非常常見的功能需求。這類效果看似簡單,其實背后都涉及到“圖層合成”的處理:如何將一個靜態或動態的圖層(如文字、圖片、動畫)與原始視頻內容進行有效疊加,并最終導出成可播放的視頻文件?

在 AVFoundation 中,這類功能主要依賴兩個關鍵能力:

  • AVMutableVideoComposition:用于控制視頻渲染過程,包括輸出尺寸、幀率、圖層結構等;
  • AVVideoCompositionCoreAnimationTool:負責將 Core Animation 中的?CALayer?圖層渲染到視頻幀中。

借助這套機制,我們不僅可以給視頻打水印、添加動態文字,還可以實現富有表現力的貼紙動畫,甚至是一些 UI 動效。

本篇文章,我們將從理論出發,深入講解 AVFoundation 圖層合成的實現原理與關鍵組件;在下一篇中,我們將結合 Demo,動手實現一個視頻添加水印與貼紙的完整流程。

二、AVMutableVideoComposition 簡介

在 AVFoundation 中,AVMutableVideoComposition?是一個非常重要的類,它描述了如何將一個或多個視頻軌道中的幀,渲染成最終輸出的視頻幀序列。如果說?AVComposition?管理的是時間線與素材軌道的關系,那么?AVMutableVideoComposition?就是對最終“視覺輸出效果”的控制。

簡單來說,它負責解決兩個問題:

  1. 輸出的視頻畫面長什么樣?(尺寸、幀率、背景、變換等)
  2. 每一幀的渲染順序與合成邏輯是什么?(比如加濾鏡、加圖層)

2.1 主要屬性解析

??renderSize

  • 指定最終輸出的視頻畫面尺寸(例如:1080x1920)。
  • 所有圖層都必須在這個坐標系統內進行布局。
  • 如果設置錯誤,可能導致圖層不顯示、導出失敗等問題。

??frameDuration

  • 控制每一幀的時間間隔,常見為?CMTime(value: 1, timescale: 30),表示 30fps。
  • 若設置與素材幀率不符,可能會影響播放流暢度。

??instructions

  • 類型為?[AVVideoCompositionInstructionProtocol],用于指定視頻軌道在不同時間段的渲染邏輯。
  • 每個?AVVideoCompositionInstruction?可以配置一個或多個?AVVideoCompositionLayerInstruction。例如:視頻的縮放、旋轉、透明度變化;多視頻軌的合成順序。

2.2 在視頻編輯流程中的作用

可以把?AVMutableVideoComposition?理解為“渲染層上的指揮官”:

  • 它并不直接操作素材,而是告訴 AVFoundation:“請按這個尺寸、順序和方式來渲染畫面。”
  • 你可以在其上套用濾鏡、疊加文字、添加動畫圖層等。

配合使用?AVVideoCompositionCoreAnimationTool,它甚至可以將 UIKit/CoreAnimation 的圖層(如?CALayer、CATextLayer、CAShapeLayer)渲染進每一幀視頻中,從而實現豐富的視覺效果。

2.3 一個最簡單的使用例子(代碼預覽)

let videoComposition = AVMutableVideoComposition()
videoComposition.renderSize = CGSize(width: 1080, height: 1920)
videoComposition.frameDuration = CMTime(value: 1, timescale: 30)
videoComposition.instructions = [mainInstruction]

這個對象可以作為參數傳給?AVAssetExportSession,用于控制導出時的畫面合成方式。

三、添加圖層的關鍵機制:Core Animation Tool

雖然?AVMutableVideoComposition?能夠控制視頻渲染的尺寸和幀率,但它本身并不負責圖層的繪制。如果我們想在視頻中疊加水印、文字、貼紙甚至動畫,必須借助 AVFoundation 提供的圖層合成機制 ——?AVVideoCompositionCoreAnimationTool。

這個工具類是連接 AVFoundation 與 Core Animation 的橋梁,它允許我們把?CALayer?圖層樹渲染到每一幀視頻畫面上,從而實現豐富的視覺效果。

3.1 什么是 AVVideoCompositionCoreAnimationTool?

AVVideoCompositionCoreAnimationTool?是?AVVideoComposition?的一個可選屬性,用于在視頻導出時,把你設置的圖層渲染到輸出幀中。

其典型用途包括:

  • 添加圖片水印(如 Logo)
  • 添加文本(標題、時間戳)
  • 添加動畫貼紙、表情
  • 使用 CAAnimation 實現復雜動畫效果(如移動、淡入淡出等)

一句話總結:它讓你能“畫在視頻上”

3.2 如何使用 Core Animation Tool?

使用它的方式非常固定,關鍵是構造一個圖層結構并設置:

videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer,in: parentLayer
)
  • videoLayer:承載視頻幀的圖層,系統會把每幀畫面渲染到這個圖層上。
  • parentLayer:容器圖層,包含?videoLayer?以及其他你希望疊加的圖層(如水印圖層、文字圖層等)。

最終,整個圖層結構被合成渲染到每一幀輸出畫面中。

3.3 圖層結構示意圖

推薦使用如下結構(從上到下是層級):

parentLayer
├── videoLayer ? ? ?(負責承載視頻幀)
├── watermarkLayer ?(圖片水印)
├── textLayer ? ? ? (文字/字幕)
└── animationLayer ?(動態貼紙等)

?? 注意:所有圖層的尺寸都應該與?videoComposition.renderSize?完全一致,否則可能出現錯位、無法渲染等問題。

3.4 坐標系說明(易錯點)

  • CALayer?使用的是?左上角為 (0, 0)?的坐標系(與 UIKit 相反)
  • 所有位置、尺寸都要基于?renderSize?計算,比如:
watermarkLayer.frame = CGRect(x: renderSize.width - 100, y: renderSize.height - 100, width: 80, height: 80)
  • 圖層默認透明背景,疊加時會自動覆蓋下方內容

3.5 添加動畫圖層

由于?CALayer?支持?CAAnimation,你可以給圖層添加任意動畫,例如:

let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 1.0
animation.beginTime = AVCoreAnimationBeginTimeAtZero + 2.0
animation.isRemovedOnCompletion = false
animation.fillMode = .forwards
watermarkLayer.add(animation, forKey: "fadeIn")

結合?beginTime,你甚至可以控制水印在第幾秒出現,第幾秒消失,做出“動態水印”效果。

3.6 常見問題與陷阱

問題

原因

圖層不顯示

坐標錯誤 / 圖層尺寸不匹配 / 未正確加入 parentLayer

圖層變形

renderSize 與原素材尺寸不一致 / 圖層未正確拉伸

動畫無效

沒設置?beginTime?/ 忘記設置?fillMode?/ 圖層動畫未添加成功

導出失敗

圖層中含有不支持的動畫類型(建議使用基本動畫)

四、視頻圖層合成的基本結構

在上一節中我們了解了?AVVideoCompositionCoreAnimationTool?的作用和基本用法。接下來我們來具體拆解:如何構建圖層結構,將多個內容合成到視頻畫面中

在 AVFoundation 的圖層合成中,最常見的操作就是:將原始視頻幀作為底層圖層,并在其上疊加其他視覺元素,例如圖片水印、文本信息、動畫貼紙等。

這背后依賴的是 Core Animation 的圖層樹結構。

4.1 推薦圖層結構

通常我們推薦使用如下的分層方式:

let parentLayer = CALayer()
let videoLayer = CALayer()
let watermarkLayer = CALayer()
let textLayer = CATextLayer()
// 可選:更多圖層(如動態貼紙、時間戳)parentLayer.frame = CGRect(origin: .zero, size: renderSize)
videoLayer.frame = parentLayer.frame
watermarkLayer.frame = CGRect(x: ..., y: ..., width: ..., height: ...)
textLayer.frame = CGRect(x: ..., y: ..., width: ..., height: ...)// 添加順序很關鍵
parentLayer.addSublayer(videoLayer)       // 視頻在底層
parentLayer.addSublayer(watermarkLayer)   // 水印在上
parentLayer.addSublayer(textLayer)        // 文字層

然后將這個?parentLayer?和?videoLayer?一起交給?AVVideoCompositionCoreAnimationTool:

videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer,in: parentLayer
)

4.2 圖層尺寸與坐標系說明

構建圖層結構時,最容易出錯的是尺寸和坐標系

屬性

要點說明

尺寸(frame)

所有圖層尺寸必須與?renderSize?匹配,否則位置和縮放會異常

坐標系

Core Animation 的坐標原點在左上角,y 值向下增長(與 UIKit 相反)

圖片縮放

圖層內容如圖片需要根據目標尺寸進行適配,否則可能拉伸或被裁剪

4.3 各類圖層添加方式

? 圖片水印(Logo)

let image = UIImage(named: "logo")!
let watermarkLayer = CALayer()
watermarkLayer.contents = image.cgImage
watermarkLayer.frame = CGRect(x: renderSize.width - 100, y: 20, width: 80, height: 80)
watermarkLayer.opacity = 0.8

? 文本圖層(如標題、用戶名)

let textLayer = CATextLayer()
textLayer.string = "演示視頻 by Pang"
textLayer.fontSize = 24
textLayer.foregroundColor = UIColor.white.cgColor
textLayer.alignmentMode = .center
textLayer.frame = CGRect(x: 0, y: 20, width: renderSize.width, height: 40)
textLayer.contentsScale = UIScreen.main.scale

? 動態圖層(貼紙/動畫)

let stickerLayer = CALayer()
stickerLayer.contents = UIImage(named: "star")?.cgImage
stickerLayer.frame = CGRect(x: 30, y: 30, width: 50, height: 50)// 添加簡單動畫(如旋轉)
let rotation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.fromValue = 0
rotation.toValue = Double.pi * 2
rotation.duration = 2
rotation.repeatCount = .infinity
stickerLayer.add(rotation, forKey: "rotate")

4.4 小貼士:透明背景與抗鋸齒

  • CALayer?默認背景是透明的,無需特殊設置
  • 為避免文字模糊,textLayer.contentsScale?建議設置為?UIScreen.main.scale
  • 所有圖層請避免使用?masksToBounds = true,以免意外裁剪動畫或子圖層

4.5 圖層生命周期說明

這些圖層的渲染,僅在視頻導出(或播放合成 AVPlayerItem 時)被一次性處理。它們在導出完成后就“燒錄”進視頻文件中,無法再修改或交互。因此:

  • 不支持用戶拖動、點擊圖層
  • 動畫必須提前規劃好時間、路徑、透明度等

五、動態內容支持

前面我們已經構建好了圖層結構,添加了靜態的水印圖像和文字圖層。但在實際項目中,用戶往往希望能看到**“動”的效果**:

比如水印淡入淡出、字幕逐行滾動、貼紙旋轉跳動……這些都需要借助 Core Animation 來實現動態圖層合成

AVFoundation 本身并不負責動畫邏輯,而是通過?AVVideoCompositionCoreAnimationTool?把 Core Animation 的動畫“燒錄”進每一幀輸出畫面中。因此,我們完全可以使用 Core Animation 的動畫能力,來制作動態效果圖層

5.1 常見的動態圖層形式

動態效果

實現方式

水印淡入淡出

CABasicAnimation?作用于?opacity

貼紙旋轉

CABasicAnimation?作用于?transform.rotation.z

圖層移動

CABasicAnimation?作用于?position

路徑動畫

CAKeyframeAnimation?配合貝塞爾曲線路徑

動畫序列幀

定時切換?contents?或使用?CAKeyframeAnimation

動態文本滾動

修改?position.y?并設置線性動畫

5.2 控制動畫時機的關鍵參數

每個動畫圖層必須明確告訴系統:什么時候開始動、動多久。這依賴幾個重要參數:

??beginTime

表示動畫的起始時間(相對于視頻時間的 0 秒)

  • 通常設置為:AVCoreAnimationBeginTimeAtZero + 1.0(表示從第 1 秒開始)
  • 如果不設置,動畫可能不會生效

??duration

動畫持續時長(單位為秒)

??fillMode

控制動畫結束后的狀態(常用?.forwards)

??isRemovedOnCompletion

設置為?false?可讓動畫結束后保持最終狀態(比如淡入后常駐)

5.3 示例:水印淡入

let fadeIn = CABasicAnimation(keyPath: "opacity")
fadeIn.fromValue = 0
fadeIn.toValue = 1
fadeIn.duration = 1.0
fadeIn.beginTime = AVCoreAnimationBeginTimeAtZero + 2.0
fadeIn.isRemovedOnCompletion = false
fadeIn.fillMode = .forwards
watermarkLayer.add(fadeIn, forKey: "fadeIn")

此動畫表示:第 2 秒開始,1 秒內從透明漸變為可見

5.4 示例:貼紙旋轉

let rotate = CABasicAnimation(keyPath: "transform.rotation.z")
rotate.fromValue = 0
rotate.toValue = Double.pi * 2
rotate.duration = 2
rotate.repeatCount = .infinity
stickerLayer.add(rotate, forKey: "rotate")

這段代碼會讓貼紙圖層無限循環地旋轉。

5.5 示例:沿路徑移動

let move = CAKeyframeAnimation(keyPath: "position")
move.path = UIBezierPath(ovalIn: CGRect(x: 100, y: 100, width: 200, height: 200)).cgPath
move.duration = 4.0
move.beginTime = AVCoreAnimationBeginTimeAtZero + 1.0
move.repeatCount = 1
move.fillMode = .forwards
move.isRemovedOnCompletion = false
animatedLayer.add(move, forKey: "orbit")

你甚至可以讓圖層沿橢圓路徑飛行!

5.6 動態文本:標題/字幕動效

let titleLayer = CATextLayer()
titleLayer.string = "AVFoundation 視頻合成演示"
titleLayer.fontSize = 28
titleLayer.foregroundColor = UIColor.white.cgColor
titleLayer.alignmentMode = .center
titleLayer.frame = CGRect(x: 0, y: renderSize.height, width: renderSize.width, height: 40)let scroll = CABasicAnimation(keyPath: "position.y")
scroll.fromValue = renderSize.height + 20
scroll.toValue = renderSize.height - 80
scroll.duration = 2
scroll.beginTime = AVCoreAnimationBeginTimeAtZero + 1.0
scroll.fillMode = .forwards
scroll.isRemovedOnCompletion = false
titleLayer.add(scroll, forKey: "scrollIn")

讓標題文字從屏幕底部“滑入”到中間位置,很適合視頻片頭效果。

5.7 動態圖層注意事項

注意點

說明

圖層必須添加到?parentLayer?中

否則不會渲染

動畫必須設置?beginTime?和?fillMode

防止動畫不播放或一閃而過

所有動畫基于 Core Animation 離屏渲染

導出時性能消耗較高,建議控制動畫數量和復雜度

導出時間可能顯著增加

動畫越復雜,合成時間越長

六、結語

本文我們圍繞?AVMutableVideoComposition?和?AVVideoCompositionCoreAnimationTool,深入講解了視頻圖層合成的核心機制。無論是靜態水印、動態貼紙,還是滑入滑出的字幕效果,其本質都是通過構建一個完整的?CALayer樹,并借助 AVFoundation 渲染到每一幀視頻中。

總結起來,視頻圖層合成的核心步驟包括:

  1. 使用?AVMutableVideoComposition?配置輸出尺寸與幀率;
  2. 構建?parentLayer?圖層樹,添加視頻層、圖像層、文本層等;
  3. 通過?AVVideoCompositionCoreAnimationTool?將圖層合成綁定到視頻;
  4. 根據需要添加?CABasicAnimation?或?CAKeyframeAnimation?實現動效;
  5. 最終配合?AVAssetExportSession?導出合成后的視頻文件。

雖然過程看起來略顯繁瑣,但一旦理解其中原理,就能靈活實現各種視覺疊加效果,為視頻內容增添專業感與表現力。

下一篇文章中,我們將結合實戰 Demo,實現一個支持添加動態水印與字幕動畫的導出工具,歡迎繼續關注~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90188.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90188.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90188.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android NDK與JNI深度解析

核心概念定義:NDK (Native Development Kit): 是什么: 一套由 Google 提供的工具集合。目的: 允許 Android 開發者使用 C 和 C 等原生(Native)語言來實現應用程序的部分功能。包含內容: 交叉編譯器&#xf…

Golang各版本特性

1. Go各版本特性 | FeelingLife 2. https://chatgpt.com/share/68808f58-ae5c-800a-8153-5358098f301b 3.https://tonybai.com/2024/11/14/go-map-use-swiss-table/

HTML 轉 Word API 接口

HTML 轉 Word API 接口 支持網頁轉 Word,高效轉換為 Word,提供永久鏈接。 1. 產品功能 超高性能轉換效率;支持將傳遞的 HTML 轉換為 Word,支持 HTML 中的 CSS 格式在 Word 文檔中的呈現;支持傳遞網站的 URL&#xff…

Lucid Search: 極簡、隱私友好的問答式搜索引擎技術解析

Lucid Search: 極簡、隱私友好的問答式搜索引擎技術解析 產品定位與價值主張 Lucid Search 是一款革命性的問答式搜索引擎,其核心價值在于: 極簡體驗:無賬戶、無廣告、前端完全靜態隱私保護:不寫入 Cookie、不記錄 IP、無追蹤即…

卷積神經網絡:模型評估標準

一、分類模型評價指標在模型評估中,有多個標準用于衡量模型的性能,這些標準包括準確率(Accuracy)、精確率(Precision)、召回率(Recall)、F1 分數(F1-Score)等…

【前端工程化】前端開發中想做好發布管理可以從哪些方面著手?

在企業級后臺系統中,發布管理是整個開發流程的最終環節,也是最為關鍵的一環。它不僅涉及代碼構建完成后的部署操作,還包括版本控制、灰度發布、回滾機制等保障系統穩定性的措施。 本文主要圍繞發布流程設計、版本控制、部署方式、灰度策略和回…

替分布式=成本下降50% !

在數字化轉型的浪潮中,數據庫作為醫療信息系統的“心臟”,其穩定性與效率直接關乎醫療服務的質量。2024年10月30日,綿陽市第三人民醫院集成平臺的CDR數據庫成功從分布式數據庫Citus切換為國產集中式數據庫KingbaseES,并穩定運行至…

【Linux系統編程】基礎指令

基礎指令1. adduser指令&&passwd指令2. userdel指令3. pwd指令4. ls指令5. cd指令6. tree指令7. touch指令8. mkdir指令9. rmdir指令&&rm指令10. man指令11. cp指令12. mv指令13. cat指令14. more指令15. less指令16. head指令17. tail指令18. date指令19. cal…

區塊鏈之以太坊Hardhat開發框架——部署在windows為例

Hardhat 提供了一個靈活且易于使用的開發環境,可以輕松地編寫、測試和部署智能合約。Hardhat還內置了Hardhat 網絡(Hardhat Node),它是為開發而設計的本地以太坊網絡。 下面是hardhat的官方文檔 https://hardhat.org/hardhat-ru…

Ubuntu 1804 編譯ffmpeg qsv MediaSDK libva 遇到的問題記錄

之前都是 用的xeon服務器的cpu 不支持intel QSV 硬件加速 最近把自己的 14年買的pc機裝上了ubuntu 1804 然后準備開啟ffmpeg qsv 硬件加速功能 CPU i3-4170 內存DDR3 16G 硬盤機械盤500G 主板ASUS B85M-G首先安裝vainfo工具apt install vainfo裝完提示如下出錯了 網上說是…

Elasticsearch(ES)介紹和安裝

目錄 一、Elasticsearch(ES)介紹 1.為什么需要單獨的搜索服務 2.全文檢索 3.Elasticsearch簡介 1.Elasticsearch的特點 2.應用場景 3.ElasticSearch數據的存儲和搜索原理 二、Elasticsearch(ES)安裝 1、拉取鏡像 2、創建目錄并給目錄賦權 3、創建并編輯配置文件 4、…

html結構解析

<!DOCTYPE html>&#xff1a;聲明為 HTML5 文檔 <html lang"zh-CN">&#xff1a;根元素&#xff0c;指定頁面語言為中文 <meta charset"UTF-8">&#xff1a;設置字符編碼&#xff0c;確保中文正常顯示 <meta name"viewport"…

面試150 最大子數組和

思路 貪心法&#xff1a;設定最小標志result為float(‘-inf’),遍歷一次數組元素進行求和&#xff0c;如果當前元素大于result&#xff0c;則更新result的值&#xff0c;如果sum小于0&#xff0c;則重新置0進行計算&#xff0c;最后返回result class Solution:def maxSubArray(…

MyBatis動態SQL實戰:告別硬編碼,擁抱智能SQL生成

MyBatis動態SQL實戰&#xff1a;告別硬編碼&#xff0c;擁抱智能SQL生成在電商平臺的用戶管理模塊中&#xff0c;需要面對多種不同的用戶查詢組合條件。當使用傳統的硬編碼SQL方式時&#xff0c;代碼膨脹到了2000多行&#xff0c;維護成本極高。而引入MyBatis動態SQL后&#xf…

Web前端開發:JavaScript遍歷方法詳解與對比

1. 傳統 for 循環const arr [10, 20, 30]; for (let i 0; i < arr.length; i) {console.log(索引 ${i}: 值 ${arr[i]}); } // 輸出&#xff1a; // 索引 0: 值 10 // 索引 1: 值 20 // 索引 2: 值 30特點&#xff1a;最基礎的循環&#xff0c;可通過索引精準控制適用場景&…

Python 爬蟲(一):爬蟲偽裝

目錄 1 簡介2 偽裝策略 2.1 Request Headers 問題2.2 IP 限制問題 3 總結 1 簡介 對于一些有一定規模或盈利性質比較強的網站&#xff0c;幾乎都會做一些防爬措施&#xff0c;防爬措施一般來說有兩種&#xff1a;一種是做身份驗證&#xff0c;直接把蟲子擋在了門口&#xff…

TODAY()-WEEKDAY(TODAY(),2)+1

這個Excel公式 TODAY()-WEEKDAY(TODAY(),2)1 用于計算 當前周的周一日期。下面詳細解釋它的邏輯和用法&#xff1a;公式解析TODAY()返回當前日期&#xff08;例如今天是2023年12月20日&#xff0c;則 TODAY() 2023/12/20&#xff09;。WEEKDAY(TODAY(), 2)計算當前日期是星期幾…

Fast Frequency Estimation Algorithm by Least Squares Phase Unwrapping

I. 引言 單個含噪正弦信號的頻率估計是一個研究已久的問題&#xff0c;并有多種應用[1]。在高斯白噪聲假設下&#xff0c;最大似然(ML)頻率估計器是Rife和Boorstyn [2]中提出的周期圖估計器&#xff0c;其中傅里葉變換用于搜索周期圖的最大值。周期圖估計器被廣泛認為是單頻估計…

C語言常見的預定符號常量

C語言常見的預定符號常量C 語言提供了豐富的預定義符號常量&#xff0c;分布在不同頭文件中&#xff0c;用于獲取編譯信息、數值范圍、浮點特性等關鍵信息。以下是常見預定義符號常量的分類總結&#xff1a;一、預定義宏&#xff08;編譯時信息&#xff09;由編譯器自動定義&am…

【2025】使用vue構建一個漂亮的天氣卡片

1. 核心框架&#xff1a;Vue Vue 以其輕量、易用、響應式數據綁定的特點&#xff0c;非常適合快速構建這類小型界面組件。即使是直接通過 CDN 引入&#xff0c;也能高效開發&#xff0c;降低項目復雜度&#xff0c;無需搭建完整工程化環境 。 2. 網絡請求&#xff1a;Axios 用于…