引言
博客专栏链接:AVFoundation架构与实践
博客专栏源码链接:AVFoundation-建议转存大量实战源码
在前两篇博客《音视频裁剪与拼接的实战实现》中,我们基于 AVFoundation 成功完成了素材的裁剪与时间线拼接,初步构建了一个可播放、可导出的编辑系统。至此,视频的“画面结构”已经具备基础处理能力。
但对于一个真正可用的视频编辑系统而言,声音的重要性不亚于画面。配乐、原声、过渡音效的融合,不仅提升观感体验,更直接决定作品的情绪氛围。
本篇将继续深入 AVFoundation 的音频处理能力,聚焦以下几个关键问题:
- 如何为视频添加一段背景音乐?
- 原声和背景乐能否同时存在?如何混合播放?
- 如何控制音轨的音量?比如背景音乐淡入淡出、特定时间段静音?
我们将从原理层面理解 AVMutableAudioMix 与 AVMutableAudioMixInputParameters 的职责,逐步拆解多音轨合成与动态音量控制的实现方式。
在下一篇实战部分,我们还将结合 Demo 工程落地这些功能,实现一个真正具备“声音设计能力”的视频编辑器。
为视频添加背景音乐
1. 背景音乐的本质:额外的音频轨
在 AVFoundation 中,背景音乐的添加,并不是修改原始素材的音轨,而是往 AVMutableComposition 中添加一条新的音频轨道(AVMutableCompositionTrack)。最终生成的合成内容可以包含多条音频轨,例如:
- 原始视频自带的原声音轨(通常从 videoAsset.tracks(withMediaType: .audio) 获取)
- 新增的背景音乐音轨(来自独立的音频资源)
AVFoundation 支持多个音频轨同时播放,混合的逻辑在后续播放或导出阶段由 AVAudioMix 负责处理(详见后文)。因此,只要正确添加音轨并保证时间对齐,我们就可以轻松实现背景音乐的合成。
2. 添加背景音乐音轨的关键代码
以下是一个通用的背景音乐插入方法,负责将一段背景音乐资源插入到合成轨道中:
func addBackgroundMusic(to composition: AVMutableComposition, asset: AVAsset, at startTime: CMTime = .zero) {
// 获取背景音乐的音频轨道
guard let musicTrack = asset.tracks(withMediaType: .audio).first else { return }
// 计算插入时长:避免背景音乐超过视频时长
let duration = min(asset.duration, composition.duration - startTime)
// 创建新的音频轨道,并插入音频内容
if let bgmTrack = composition.addMutableTrack(
withMediaType: .audio,
preferredTrackID: kCMPersistentTrackID_Invalid
) {
try? bgmTrack.insertTimeRange(
CMTimeRange(start: .zero, duration: duration),
of: musicTrack,
at: startTime
)
}
}
说明:
- composition:目标合成容器;
- asset:背景音乐的音频资源,通常为 .mp3 或 .m4a 格式的本地音频文件;
- startTime:背景音乐开始插入的时间点(可用于实现延迟播放);
- 插入的 duration 不应超过视频本身的时长,避免“音乐比画面长”的问题;
- 可多次调用此方法添加多个音轨,实现复合音效。
音量控制机制解析
1. 为什么需要音量控制?
在多音轨合成中,声音并不是“简单相加”的问题:
- 背景音乐过响,可能会掩盖原始对白;
- 缺乏淡入淡出,可能导致音频突兀;
- 有时我们希望某一时间段背景音乐静音,仅保留原声。
这些场景的本质需求是:在不修改音轨内容的前提下,动态控制不同轨道在不同时刻的音量。
而 AVFoundation 正好提供了一个结构清晰、功能灵活的方案:AVMutableAudioMix。
2. AVMutableAudioMix 的角色
AVMutableAudioMix 是一个“音轨混音参数容器”,可以附加到:
- AVPlayerItem.audioMix(用于预览)
- AVAssetExportSession.audioMix(用于导出)
它自身不控制音量,而是持有一组 AVMutableAudioMixInputParameters,每一组参数对应一条音轨。
3. AVMutableAudioMixInputParameters:控制音轨音量的核心
基本使用流程
3.1 针对某条音轨的 trackID 创建一组参数:
let parameters = AVMutableAudioMixInputParameters(track: audioTrack)
3.2 通过以下两种方式设置音量:
固定音量(整条音轨一个音量):
parameters.setVolume(0.5, at: .zero)
渐变音量(支持淡入/淡出):
parameters.setVolumeRamp(fromStartVolume: 0.0, toEndVolume: 1.0, timeRange: CMTimeRange(start: .zero, duration: CMTime(seconds: 3, preferredTimescale: 600)))
3.3 创建 AVMutableAudioMix 并添加参数:
let audioMix = AVMutableAudioMix()
audioMix.inputParameters = [parameters]
4. 多段音量控制:组合使用 setVolumeRamp
可以多次调用 setVolumeRamp 设置多个时间段的音量变化。例如:
let timeRange1 = CMTimeRange(start: .zero, duration: CMTime(seconds: 2, preferredTimescale: 600))
parameters.setVolumeRamp(fromStartVolume: 0.0, toEndVolume: 1.0, timeRange: timeRange1)
let timeRange2 = CMTimeRange(start: CMTime(seconds: 8, preferredTimescale: 600), duration: CMTime(seconds: 2, preferredTimescale: 600))
parameters.setVolumeRamp(fromStartVolume: 1.0, toEndVolume: 0.0, timeRange: timeRange2)
上述代码实现了:
- 前 2 秒淡入;
- 第 8~10 秒淡出;
- 其他时段保持满音量。
5 设置 AudioMix 到播放器或导出器
播放时预览:
playerItem.audioMix = audioMix
导出时应用混音效果:
exportSession.audioMix = audioMix
注意:AVAudioMix 不会改变 AVMutableComposition 本身的数据,只影响播放/导出效果。
小结与预告
在本篇文章中,我们围绕“为视频添加背景音乐与实现音量控制”的核心问题,从原理层面展开了详细解析:
- 我们了解了如何通过向 AVMutableComposition 添加新的音频轨,实现背景音乐与原声的并存;
- 借助 AVMutableAudioMix 与 AVMutableAudioMixInputParameters,我们能够精准控制每一条音轨在任意时间点的音量;
- 包括淡入、淡出、静音、降低背景音乐等常见场景,都可以通过简单的 setVolumeRamp 调用实现。
这些能力共同构成了一个视频编辑系统在音频层面的“基础表达力”。
在下一篇实战篇中,我们将基于当前 AVFoundation 编辑框架的 Demo 工程,带你一步步实现以下功能:
- 给视频添加背景音乐;
- 控制原声与背景音乐的相对音量;
- 实现背景音乐的淡入淡出效果;
- 在播放或导出中正确应用混音效果。
让我们在代码中把这些理论全部落地,真正做出一个“有声音设计感”的视频!