一、功能目標回顧
在理論篇中,我們系統地介紹了如何使用 AVFoundation 添加背景音樂音軌,并通過?AVMutableAudioMix?與?AVMutableAudioMixInputParameters?實現多音軌混音與音量控制。我們了解了諸如淡入淡出、靜音控制、動態音量曲線等核心技術細節。
本篇將以實際代碼為基礎,結合我們之前構建的 AVFoundation 編輯 Demo 工程,落地實現以下功能:
1. 為視頻添加背景音樂
- 支持用戶在時間線上額外指定一段音頻資源;
- 背景音樂可以與原聲音軌同時存在,并被正確插入合成軌中。
2. 多音軌合成(原聲 + 背景樂)
- 原聲與背景音樂將分別被插入不同的音頻軌道;
- 最終合成時,兩條音軌將同時輸出,并支持混音控制。
3. 控制音軌音量
- 可分別為原聲與背景音樂設置不同的音量級別;
- 背景音樂默認比原聲略低,以避免搶占對白。
4. 實現背景音樂淡入淡出
- 支持設置淡入時長(如:前2秒從0過渡到1);
- 支持設置淡出時長(如:最后3秒從1降到0);
- 音量變化基于時間段動態計算,提升用戶聽覺體驗。
5. 支持播放與導出場景下的音頻混音
- 混音效果不僅適用于?AVPlayerItem?播放;
- 也可用于?AVAssetExportSession?導出,確保輸出視頻具備完整聲音效果。
這些功能將逐步融入我們現有的合成架構中,既保持結構清晰,也為后續功能擴展(如多段配樂、音效插入、音量自動化)打下良好基礎。
二、Demo 架構回顧與準備工作
在我們此前構建的 AVFoundation 編輯 Demo 中,整體設計圍繞「可組合、可導出、可復用」展開,核心接口抽象清晰,便于后續拓展新的能力。為了實現背景音樂與音量控制,我們將基于現有結構進行適度擴展。
2.1 原有架構回顧
此前的編輯系統大致由以下幾個核心組件構成:
- PHComposition 協議:定義合成結構應提供的能力:生成?AVPlayerItem?與?AVAssetExportSession。
- PHBasicComposition:基于?AVMutableComposition?構建的默認合成模型,用于拼接視頻與原聲音軌。
- PHTimeLine:?用于描述時間軸上出現的媒體資源,包括?videoItems(視頻片段)和?audioItems。
- PHBaseCompositionBuilder:負責將?PHTimeLine?構建為一個?PHComposition?實例。
該結構已經支持了基礎的剪輯與拼接能力,但尚未具備音頻混音與動態控制功能。
2.2 新增音頻混音能力:架構擴展方案
為了支持背景音樂與音量控制,我們將進行以下結構升級:
? 新增:PHAudioMixComposition
- 遵循?PHComposition?協議
- 代替原有的PHBasicComposition
- 在原有?AVMutableComposition?基礎上,添加對?AVMutableAudioMix?的支持
- 對外提供?playerItem?和?exportSession?接口,并自動附加混音配置
? 新增:PHAudioMixCompositionBuilder
- 遵循?PHCompositionBuilder?協議
- 代替原有的?PHBaseCompositionBuilder
- 負責將?PHTimeLine?中的視頻、音頻資源統一合成,同時構建對應的音量控制參數(淡入淡出等)
- 返回?PHAudioMixComposition?實例
? 擴展:PHTimeLine?添加背景音樂支持
class PHTimeLine: NSObject {/// 視頻資源數組var videoItmes = [PHVideoItem]()/// 音頻資源數組var audioItems = [PHAudioItem]()/// 背景音樂var musicItems = [PHMusicItem]()}
2.3 構建與導出流程調整
通過上述結構升級,我們的播放與導出流程也將相應調整:
原流程:
PHBaseCompositionBuilder → PHBasicComposition → AVPlayerItem / AVAssetExportSession
新流程(支持音量控制):
PHAudioMixCompositionBuilder → PHAudioMixComposition(包含 AVAudioMix) → AVPlayerItem / AVAssetExportSession
最終,在用戶層只需更換構建器類,即可無感接入新的混音邏輯。
三、添加背景音樂與構建混音輸出
在本節中,我們正式將理論篇中的混音控制能力落地到 Demo 架構中,借助兩個核心類的設計,全面實現了“添加背景音樂 + 音量控制 + 支持播放與導出”的閉環。
3.1?PHAudioMixComposition:音頻混合合成對象
PHAudioMixComposition?作為最終的合成輸出載體,遵循?PHComposition?協議,提供兩大能力:
- 構建可播放的?AVPlayerItem;
- 構建可導出的?AVAssetExportSession。
其核心結構如下:
class PHAudioMixComposition: PHComposition {private var audioMix: AVAudioMixprivate var composition: AVCompositioninit(audioMix: AVAudioMix, composition: AVComposition) {self.audioMix = audioMixself.composition = composition}func makePlayableItem() -> AVPlayerItem? {guard let asset = composition.copy() as? AVAsset else { return nil }let playerItem = AVPlayerItem(asset: asset)playerItem.audioMix = audioMixreturn playerItem}func makeExportSession(presetName: String) -> AVAssetExportSession? {guard let asset = composition.copy() as? AVAsset else { return nil }let session = AVAssetExportSession(asset: asset, presetName: presetName)session?.audioMix = audioMixreturn session}
}
通過統一附加?audioMix,我們實現了音量變化效果在播放與導出兩個流程中保持一致。
3.2?PHAudioMixCompositionBuilder:混音構建器
該類實現了?PHCompositionBuilder?協議,是實際執行素材拼接與混音參數構建的主要模塊:
class PHAudioMixCompositionBuilder: PHComositionBuilder {private let composition = AVMutableComposition()private let timeLine: PHTimeLineinit(timeLine: PHTimeLine) {self.timeLine = timeLine}func buildComposition() -> (any PHComposition)? {_ = self.addTrack(with: .video, mediaItems: timeLine.videoItmes)_ = self.addTrack(with: .audio, mediaItems: timeLine.audioItems)let musicTrack = self.addTrack(with: .audio, mediaItems: timeLine.musicItems)guard let musicTrack = musicTrack else { return nil }guard let audioMix = self.buildAudioMix(track: musicTrack) else { return nil }return PHAudioMixComposition(audioMix: audioMix, composition: composition)}
}
在合成構建流程中,PHAudioMixCompositionBuilder?完成了以下幾個關鍵任務:
- 統一插入所有視頻、音頻軌道;
- 單獨處理背景音樂軌;
- 構建 AVAudioMixInputParameters 來實現音量變化控制;
- 最終生成 PHAudioMixComposition 返回給外部使用。
3.3 構建混音參數的關鍵邏輯
在?buildAudioMix?中,我們讀取了?PHTimeLine.musicItems?中的首個?PHAudioItem,并遍歷其音量控制曲線?volumeAutomation:
private func buildAudioMix(track: AVMutableCompositionTrack) -> AVAudioMix? {guard let musicItem = self.timeLine.musicItems.first else { return nil }let parameters = AVMutableAudioMixInputParameters(track: track)for automation in musicItem.volumeAutomation {parameters.setVolumeRamp(fromStartVolume: automation.startVolume, toEndVolume: automation.endVolume, timeRange: automation.timeRange)}let audioMix = AVMutableAudioMix()audioMix.inputParameters = [parameters]return audioMix
}
這段邏輯確保我們可以靈活地:
- 控制音量隨時間變化(淡入、淡出、靜音段落等);
- 支持將多個?volumeAutomation?分段組合成完整的控制曲線;
- 保持配置結構可擴展、可預覽、可導出。
3.4 媒體軌道添加邏輯:支持異步加載資源
addTrack(with:mediaItems:)?方法支持批量插入素材軌,同時采用異步?loadTracks?方式加載素材:
for mediaItem in mediaItems {mediaItem.asset?.loadTracks(withMediaType: mediaType, completionHandler: { [weak self] tracks, error in// 插入邏輯...})
}
四、結語
至此,我們已經完成了為視頻添加背景音樂與控制音量的全部實戰流程。
相比理論篇中的 API 介紹與功能分析,本篇將這些能力真正融入到了項目架構中。我們通過構建新的?PHAudioMixComposition?與?PHAudioMixCompositionBuilder,讓混音效果不僅可控,而且具備良好的復用性和擴展性。
背景音樂的添加不再是“硬塞進一條音軌”,而是具備了細膩的時間控制和動態音量設計:我們可以淡入淡出、隨時間變化音量,甚至為不同片段設置不同的聽覺節奏。
這不僅豐富了視頻剪輯系統的表現力,也為后續更多音頻功能(如自動靜音、節奏分析、UI 實時控制音量等)打下了堅實基礎。
在下一篇中,我們將繼續擴展剪輯系統的能力,敬請期待。