一、功能目标回顾
在理论篇中,我们系统地介绍了如何使用 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 实时控制音量等)打下了坚实基础。
在下一篇中,我们将继续扩展剪辑系统的能力,敬请期待。