(十八)深入了解 AVFoundation-编辑:添加背景音乐与音量控制(下)——实战篇

一、功能目标回顾

在理论篇中,我们系统地介绍了如何使用 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 实时控制音量等)打下了坚实基础。

在下一篇中,我们将继续扩展剪辑系统的能力,敬请期待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/913487.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/913487.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在新机器上设置github完成内容git push

如果你在一台新的机器上git pull 仓库,完成修改,然后git push,会发现下面错误: Username for https://github.com: xiaomaolv Password for https://xiaomaolvgithub.com: remote: Support for password authentication was rem…

Rust 注释

Rust 注释 引言 Rust 编程语言以其内存安全、并发支持和高性能等特点在软件开发领域获得了广泛的关注。在Rust编程中,注释是一种非常重要的元素,它不仅可以帮助程序员理解代码,还可以提高代码的可维护性和可读性。本文将详细介绍Rust中的注释…

Flink Oracle CDC 环境配置与验证

一、Oracle 数据库核心配置详解 1. 启用归档日志(Archiving Log) Oracle CDC 依赖归档日志获取增量变更数据,需按以下步骤启用: 非CDB数据库配置: -- 以DBA身份连接数据库 CONNECT sys/password AS SYSDBA; -- …

ssh: Could not resolve hostname d: Temporary failure in name resolution

关于不能本机上传文件夹到服务器上的一个问题的记录。 scp -r "D:\***\datasets" usernamexxxxxx:接收文件夹名 一直报错:ssh: Could not resolve hostname d: Temporary failure in name resolution 反复尝试发现无果之后想起来,在传输的时候…

2025年的前后端一体化CMS框架优选方案

以下是结合技术生态、开发效率和商业落地验证,整理的2025年前后端一体化CMS框架优选方案:一、‌主流成熟框架组合‌1. ‌React Node.js (Express/Next.js)‌‌前端‌:React生态成熟,配合Redux状态管理,适合复杂后台界…

《声音的变形记:Web Audio API的实时特效法则》

用户期待更丰富、更具沉浸感的听觉体验时,基于Web Audio API实现的实时音频特效,就像是为这片森林注入了灵动的精灵,让简单的声音蜕变为震撼人心的听觉盛宴。回声特效带来空间的深邃回响,变声效果赋予声音全新的个性面貌。接下来&…

LLM场景下的强化学习【PPO】

适合本身对强化学习有基本了解 一、什么是强化学习 一句话:在当前状态(State)下,智能体(Agent)与环境(Environment)交互,并采取动作(Action)进入下一状态,过程中获得奖励(Reward,有正向有负向),从而实现从…

Python爬虫实战:研究chardet库相关技术

1. 引言 1.1 研究背景与意义 在互联网信息爆炸的时代,网络数据采集技术已成为信息获取、数据分析和知识发现的重要手段。Python 作为一种高效的编程语言,凭借其丰富的第三方库和简洁的语法,成为爬虫开发的首选语言之一。然而,在网络数据采集中,文本编码的多样性和不确定…

回溯题解——全排列【LeetCode】

46. 全排列 一、算法逻辑(逐步通顺讲解每一步思路) 该算法使用了典型的 回溯(backtracking) 状态数组 思路,逐层递归生成排列。 题目目标:给定一个无重复整数数组 nums,返回其所有可能的全排…

RICE模型或KANO模型在具体UI评审时的运用经验

模型是抽象的产物,结合场景才好说明(数据为非精确实际数据,仅供参考,勿照搬)。 ​​案例一:RICE模型解决「支付流程优化」vs「首页动效升级」优先级争议​​ ​​背景​​:APP电商模块在迭代中面临两个需求冲突——支付团队主张优化支付失败提示(减少用户流失),设计…

缓存中间件

缓存与分布式锁 即时性、数据一致要求不高的 访问量大且更新频率不高的数据 (读多,写少) 常用缓存中间件 redis Spring 如果用spring的情况下,由于redis没有受spring的管理, 则我们需要自己先写一个redis的配置类&…

大语言模型全方位解析:从基础认知到RESTful API应用

文章目录 前言一、初见大模型1.1 大语言模型基本知识了解(一)日常可能用到的大语言模型(二)大模型的作用(三)核心价值 1.2 大模型与人工智能关系1.3 大语言模型的“前世今生”与发展1.3.1 大语言模型的发展…

网安系列【11】之目录穿越与文件包含漏洞详解

文章目录 前言一 目录穿越漏洞1.1 什么是目录穿越?1.2 目录穿越的原理1.3 目录穿越的常见形式1.3.1 基本形式1.3.2 编码绕过1.3.3 绝对路径攻击 1.4 实战案例解析1.4.1 案例1:简单的目录穿越1.4.2 案例2:编码绕过 1.5 目录穿越的危害 二、文件…

uri-url-HttpServletRequest

1. 使用HttpServletRequest UrlPathHelper 解析 出 url路径 org.springframework.web.util.UrlPathHelper 是 Spring 框架中用于处理 HTTP 请求路径的一个工具类,它帮助解析和处理与请求路径相关的细节。特别是 getLookupPathForRequest(HttpServletRequest request…

Ubuntu22.04安装p4显卡 nvidia-utils-570-server 570.133.20驱动CUDA Version: 12.8

Ubuntu22.04安装p4显卡 nvidia-utils-570-server 570.133.20驱动CUDA Version: 12.8专业显卡就是专业显卡,尽管p4已经掉到了白菜价,官方的支持却一直都保持,比如它可以装上cuda12.8,这真的出乎我意料。NVIDIA Tesla P4显卡的主要情况Pascal架…

工业日志AI大模型智能分析系统-前端实现

目录 主要架构 前端项目结构 1. 核心实现代码 1.1 API服务封装 (src/api/log.ts) 1.2 TS类型定义 (src/types/api.ts) 1.3 Pinia状态管理 (src/stores/logStore.ts) 1.4 日志分析页面 (src/views/LogAnalysis.vue) 1.5 日志详情组件 (src/components/LogDetail.vue) 2…

C++内存泄漏排查

引言 C内存泄漏问题的普遍性与危害内存泄漏排查大赛的背景与目标文章结构和主要内容概述 内存泄漏的基本概念 内存泄漏的定义与类型(显式、隐式、循环引用等)C中常见的内存泄漏场景(指针管理不当、资源未释放等)内存泄漏对程序性能…

20250706-4-Docker 快速入门(上)-常用容器管理命令_笔记

一、常用管理命令1. 选项1)ls功能:列出容器常用参数:-a:查看所有容器包含退出的-q:列出所有容器ID-l:列出最新创建的容器状态使用技巧:容器很多时使用dock…

基于 Camunda BPM 的工作流引擎示例项目

项目介绍 这是一个基于 Camunda BPM 的工作流引擎示例项目,包含完整的后台接口和前端页面,实现了流程的设计、部署、执行等核心功能。 技术栈 后端 Spring Boot 2.7.9Camunda BPM 7.18.0MySQL 8.0JDK 1.8 前端 Vue 3Element PlusBpmn.jsVite 功能…

Day06_刷题niuke20250707

试卷01: 单选题 C 1. 在C中,一个程序无论由多少个源程序文件组成,其中有且仅有一个主函数main().说法是否正确? A 正确 B 错误 正确答案:A 官方解析: 在C程序设计中,一个完整的程序确实有且仅有一个main函数作为程序的入口点,这…