前面第 17 篇和第 18 篇,我们分析了 Pixelle-Video 的 TTS 语音生成和声音克隆。
到这里,声音部分已经有了第一层:
narration
↓
TTS / 声音克隆
↓
frame.audio_path
↓
每个视频片段的人声旁白
但一条短视频只有人声,通常还不够完整。
很多知识类、情绪类、故事类、产品介绍类短视频,都需要一层轻微的背景音乐来增强氛围。
所以 Pixelle-Video 在最终视频合成阶段,还支持添加 BGM。README 里也把“添加背景音乐”列为自动生成流程的一部分,并说明 WebUI 的背景音乐有三种选择:无 BGM、内置音乐、自定义音乐。
这一篇我们就专门分析:
Pixelle-Video 的背景音乐系统是怎么设计的?内置 BGM 和自定义音乐最终是如何混入视频的?
一、BGM 在 Pixelle-Video 流程中的位置
先看完整视频生成流程。
前面每个 StoryboardFrame 都会被处理成一个独立视频片段:
frame.narration
↓
TTS 生成 audio_path
↓
生成图片 / 视频素材
↓
HTML 模板合成画面
↓
生成 frame.video_segment_path
当所有 frame 都处理完成后,才进入后期合成阶段:
frame_01_segment.mp4
frame_02_segment.mp4
frame_03_segment.mp4
↓
concat_videos()
↓
拼接成完整视频
↓
可选:添加 BGM
↓
final.mp4
也就是说,BGM 不是每个 frame 单独加一次,而是在最终拼接阶段统一处理。
源码中的 StandardPipeline.post_production() 正是这样做的:先收集所有 frame.video_segment_path,然后调用 VideoService.concat_videos(),并把 bgm_path、bgm_volume、bgm_mode 一起传进去。
这一点很重要。
如果每个片段单独加 BGM,再拼接,很容易出现音乐断点、节奏割裂、片段之间音量不统一的问题。
Pixelle-Video 选择在最终视频层统一加 BGM,更符合后期制作逻辑。
二、BGM 和 TTS 的关系
Pixelle-Video 的声音系统可以分成两层。
第一层是 TTS 人声:
每个 frame 的 narration
↓
生成一段人声 audio_path
↓
和当前画面合成 segment
第二层是 BGM:
所有 segment 拼接完成
↓
对完整视频添加背景音乐
这两层不要混淆。
TTS 是内容本身。
BGM 是氛围增强。
TTS 决定每个分镜讲什么、讲多长。
BGM 不决定分镜结构,只是在最后给完整视频加一层音乐氛围。
所以 Pixelle-Video 的声音合成顺序是:
先人声
↓
再视频片段
↓
再完整视频
↓
最后混入背景音乐
这种顺序的好处是:
人声永远是主音轨,BGM 只是辅助,不会反过来影响 narration、frame duration 和 segment 合成。
三、WebUI 中的三种 BGM 模式
从使用层看,Pixelle-Video 的 BGM 主要有三种模式:
无 BGM
内置音乐
自定义音乐
README 中对这三种模式的描述很直接:无 BGM 表示纯人声解说;内置音乐表示选择预置背景音乐,例如 default.mp3;自定义音乐则是把自己的 MP3、WAV 等音乐文件放到 bgm/ 文件夹,并且可以点击“试听 BGM”进行预览。
可以理解成:
无 BGM:
final.mp4 只有 TTS 旁白,没有背景音乐。
内置音乐:
从项目自带 bgm/ 目录选择一首音乐。
自定义音乐:
用户放入自己的音乐文件,让系统在资源扫描时发现并使用。
这三种模式覆盖了大多数普通短视频场景。
如果是知识讲解、教程视频,有时不加 BGM 更干净。
如果是情绪类、故事类视频,加轻微 BGM 会更有氛围。
如果是品牌账号或固定栏目,自定义音乐能保持账号识别度。
四、参数入口:bgm_path、bgm_volume、bgm_mode
从源码角度看,BGM 进入后期合成主要靠三个参数:
bgm_path
bgm_volume
bgm_mode
在 StandardPipeline.post_production() 中,调用 VideoService.concat_videos() 时传入:
final_video_path = video_service.concat_videos(
videos=segment_paths,
output=ctx.final_video_path,
bgm_path=ctx.params.get("bgm_path"),
bgm_volume=ctx.params.get("bgm_volume", 0.2),
bgm_mode=ctx.params.get("bgm_mode", "loop")
)
源码里默认 bgm_volume 是 0.2,默认 bgm_mode 是 "loop"。
这三个参数可以这样理解:
bgm_path:
背景音乐文件名或路径。
为空时,不添加 BGM。
bgm_volume:
背景音乐音量。
默认 0.2,表示相对较低的背景音量。
bgm_mode:
背景音乐播放方式。
loop 表示循环播放。
once 表示只播放一次。
所以 Pixelle-Video 的 BGM 控制并不复杂,但已经覆盖了最关键的几个点:选哪首、声音多大、是否循环。
五、没有 BGM 时:直接拼接视频片段
先看最简单的情况:没有 BGM。
如果 bgm_path 为空,VideoService.concat_videos() 会直接拼接所有视频片段,不会再进入添加音乐的分支。源码中 concat_videos() 的参数注释也明确写到,bgm_path 是可选背景音乐路径,None 表示不加 BGM。
流程是:
segment_paths
↓
concat_videos(videos=segment_paths, bgm_path=None)
↓
_concat_demuxer() 或 _concat_filter()
↓
final.mp4
这种模式适合:
教程类视频
代码讲解视频
严肃科普视频
需要突出人声的口播视频
后续还要在剪辑软件里单独处理音乐的视频
无 BGM 的优点是干净,缺点是氛围感弱。
六、有 BGM 时:先拼接,再加音乐
如果 bgm_path 不为空,Pixelle-Video 会进入另一条流程。
源码中 VideoService.concat_videos() 的逻辑是:
1. 先把多个视频片段拼接成临时文件
2. 临时文件名类似 final_no_bgm.mp4
3. 再调用 _add_bgm_to_video()
4. 把 BGM 混入最终 output
5. 删除临时 no_bgm 文件
这一段在源码里非常清楚:如果需要 BGM,会先生成 temp_output = output.replace('.mp4', '_no_bgm.mp4'),然后拼接视频,再调用 _add_bgm_to_video(),最后删除临时文件。
完整流程可以画成这样:
frame_01_segment.mp4
frame_02_segment.mp4
frame_03_segment.mp4
↓
concat
↓
final_no_bgm.mp4
↓
_add_bgm_to_video()
↓
final.mp4
这个设计很合理。
因为 BGM 应该覆盖整条成片,而不是覆盖单个片段。
先拼接,再混音,可以让音乐贯穿完整视频。
七、为什么要生成 final_no_bgm.mp4?
final_no_bgm.mp4 是一个中间文件。
它的作用是把“视频拼接”和“BGM 混音”拆成两个步骤。
步骤一:
多个 segment → 一个完整无背景音乐视频
步骤二:
完整无 BGM 视频 + BGM → 最终视频
这样做有几个好处。
第一,逻辑清楚。
拼接视频是拼接问题。
添加 BGM 是混音问题。
两者拆开,代码更容易维护。
第二,方便排查。
如果最终视频出问题,可以先检查无 BGM 版本是否正常。
如果无 BGM 版本正常,问题大概率在音乐路径、音量或混音阶段。
第三,避免每个 segment 单独处理音乐。
如果每段都加音乐,后面再拼接,音乐会在每个片段重新开始。
统一在完整视频上加音乐,听感更自然。
第四,方便未来扩展。
如果后续要做自动配乐、音量 ducking、淡入淡出,都可以基于无 BGM 成片继续处理。
八、BGM 文件路径如何解析?
BGM 的 bgm_path 既可以是直接路径,也可以只是一个文件名。
VideoService._resolve_bgm_path() 专门负责解析音乐文件路径。源码注释中写明,它的搜索优先级是:
1. 直接路径
2. data/bgm/{filename}
3. bgm/{filename}
如果找不到,就会抛出 FileNotFoundError,并列出尝试过的路径和可用 BGM 文件。
这说明 Pixelle-Video 的 BGM 文件不是只能放在项目默认目录。
它支持两类资源:
默认资源:
bgm/
自定义资源:
data/bgm/
os_util.py 中的资源管理函数也体现了这个设计:get_resource_path("bgm", filename) 会优先查找 data/bgm 下的自定义资源,再回退到项目根目录下的默认 bgm;list_resource_files("bgm") 会合并默认目录和自定义目录,并且自定义文件优先覆盖同名默认文件。
所以,如果用户放了一个和内置音乐同名的文件到 data/bgm/,系统会优先使用用户自定义版本。
九、内置 BGM 和自定义 BGM 的本质区别
从用户角度看:
内置 BGM:
项目自带,直接选择。
自定义 BGM:
用户自己放进去,再选择。
但从源码角度看,它们最后都是一个 bgm_path。
区别只在路径解析阶段。
内置 BGM:
bgm/default.mp3
自定义 BGM:
data/bgm/my_music.mp3
当进入 VideoService._add_bgm_to_video() 时,它并不关心这首音乐来自哪里。
它只需要拿到一个真实存在的音频文件路径:
resolved_bgm
然后交给 add_bgm() 去混音。
这就是资源系统的好处:
上层只传文件名
资源层负责查找
视频层只处理真实路径
这样内置音乐和自定义音乐就能共用同一套混音逻辑。
十、Docker 场景下自定义 BGM 放哪里?
如果使用 Docker 部署,Pixelle-Video 也考虑了自定义资源持久化。
docker-compose.yml 中会把宿主机的 ./data 挂载到容器的 /app/data,注释里说明 data/ 包含 users/、bgm/、templates/、workflows/ 等自定义资源;默认资源则已经打包在镜像中,自定义资源可以覆盖默认资源。
也就是说,Docker 用户应该把自定义音乐放到类似:
./data/bgm/
而不是直接改容器里的:
/app/bgm/
因为容器里的文件可能随着重建镜像而丢失。
正确思路是:
宿主机 ./data/bgm/custom.mp3
↓
挂载到容器 /app/data/bgm/custom.mp3
↓
Pixelle-Video 资源系统优先读取 data/bgm
这个设计和模板、workflow 的自定义机制是一致的。
十一、_list_available_bgm:系统如何列出可用音乐?
VideoService._list_available_bgm() 用来列出可用 BGM 文件。
源码中它调用 list_resource_files("bgm"),然后只保留音频扩展名:
.mp3
.wav
.ogg
.flac
.m4a
.aac
最后返回排序后的文件名列表。
这说明 Pixelle-Video 的 BGM 文件并不只支持 MP3。
从路径解析和列表过滤看,它至少考虑了常见音频格式:
mp3
wav
ogg
flac
m4a
aac
不过从 WebUI 文档描述看,最常见的使用方式还是 MP3 / WAV。
实际使用时,如果追求兼容性,建议优先使用:
mp3
wav
这两个格式通常最稳定。
十二、_add_bgm_to_video:从路径解析到混音
真正添加背景音乐的入口是:
VideoService._add_bgm_to_video()
它做两件事。
第一,调用 _resolve_bgm_path(),把用户传入的 bgm_path 解析成真实文件路径。
第二,根据 bgm_mode 判断是否循环播放,然后调用 add_bgm() 完成混音。
源码里 mode == "loop" 时,loop = True;否则就是只播放一次。
简化逻辑如下:
def _add_bgm_to_video(video, bgm_path, output, volume=0.2, mode="loop"):
resolved_bgm = self._resolve_bgm_path(bgm_path)
loop = (mode == "loop")
return self.add_bgm(
video=video,
bgm=resolved_bgm,
output=output,
bgm_volume=volume,
loop=loop,
fade_in=0.0
)
这一步把用户层参数转换成视频处理层参数:
bgm_path → resolved_bgm
bgm_mode → loop
bgm_volume → bgm_volume
然后真正交给 ffmpeg 混音。
十三、add_bgm:ffmpeg 如何混合人声和背景音乐?
add_bgm() 是 BGM 混音的核心函数。
源码注释中写得很明确:它会把 BGM 添加到视频中,bgm_volume 表示背景音乐相对于原始声音的音量,loop=True 时会循环 BGM 来匹配视频时长,并且 BGM 会和原视频音频混合。
它内部的关键逻辑可以理解为:
输入视频
↓
取出原视频音频,也就是 TTS 旁白
输入 BGM
↓
必要时 stream_loop=-1 无限循环
BGM 音频
↓
volume 过滤器调低音量
原视频音频 + BGM 音频
↓
amix 混音
↓
输出 final.mp4
源码中使用的是 ffmpeg 的 amix 过滤器,并设置 duration='first',也就是输出音频长度跟随第一个输入,也就是原视频音频长度。
这点非常关键。
因为最终视频长度应该由完整视频决定,而不是由 BGM 决定。
如果 BGM 比视频长,不应该把视频拉长。
如果 BGM 比视频短,在 loop 模式下可以循环补齐。
如果不是 loop 模式,则音乐播放一次后结束。
十四、bgm_mode:loop 和 once 的区别
Pixelle-Video 的 bgm_mode 有两个主要值:
loop
once
在 _add_bgm_to_video() 中,mode == "loop" 会转成 loop=True,然后 add_bgm() 在读取 BGM 时使用 stream_loop=-1,表示无限循环;否则不循环。
可以理解成:
loop:
BGM 不够长时循环播放,直到视频结束。
once:
BGM 只播放一次,播完就没有背景音乐。
两种模式适合不同场景。
1. loop 模式
适合大多数短视频。
因为短视频长度不固定,如果 BGM 太短,loop 可以自动补齐。
30 秒视频 + 10 秒 BGM
↓
BGM 循环 3 次
优点是不会出现后半段突然没有音乐的问题。
缺点是如果 BGM 结尾和开头衔接不好,循环点可能会有跳变。
2. once 模式
适合 BGM 本身已经足够长,或者你希望音乐只出现一次的场景。
20 秒视频 + 60 秒 BGM
↓
只取前 20 秒混入最终视频
或者:
60 秒视频 + 15 秒 BGM
↓
前 15 秒有音乐,后面主要保留人声
once 模式更适合有明确音乐结构的内容,例如开场音乐、结尾音乐、短提示音等。
十五、bgm_volume:为什么默认比较低?
Pixelle-Video 在 post_production() 里传给 concat_videos() 的默认 bgm_volume 是 0.2。
这个默认值比较保守。
原因很简单:
Pixelle-Video 的主音轨是 TTS 旁白。
BGM 如果太大,会压住人声,尤其是中文口播、知识科普、教程类视频,观众听不清内容就会直接划走。
所以 BGM 音量应该遵循一个原则:
人声优先
音乐辅助
经验上可以这样理解:
0.1 - 0.2:
适合知识类、教程类、严肃口播。
0.2 - 0.3:
适合普通情绪类、故事类短视频。
0.3 以上:
需要谨慎,可能会影响人声清晰度。
当然,具体还要看原始 BGM 的响度。
有些音乐本身很响,0.2 也可能偏大。
有些音乐本身很轻,0.3 也未必明显。
所以后续如果产品化,可以增加响度标准化或自动 ducking。
十六、为什么 BGM 不参与每个 frame 的 duration?
前面讲 TTS 时,我们说 frame.duration 由 TTS 音频时长决定。
那么 BGM 会不会影响 frame.duration?
答案是:不会。
BGM 是在完整视频拼接之后统一添加的,不参与单个 frame 的生成。源码里 post_production() 是在 produce_assets() 之后执行;frame 已经生成了 video_segment_path,BGM 才通过 concat_videos() 的参数进入后期阶段。
这说明:
TTS 决定片段时长
BGM 不决定片段时长
BGM 只覆盖最终视频音轨
这种设计很合理。
因为 BGM 是背景层,不应该打乱旁白节奏。
如果音乐长度反过来决定视频长度,就会让文案、分镜和画面都变得不可控。
十七、BGM 和最终视频编码
在 add_bgm() 中,ffmpeg 输出时使用:
vcodec='copy'
acodec='aac'
audio_bitrate='192k'
源码中可以看到,视频流会尽量直接复制,而音频流重新编码为 AAC。
这说明添加 BGM 时,Pixelle-Video 的重点是处理音频,不是重新渲染视频画面。
视频画面:
尽量 copy,减少重编码损耗和耗时。
音频:
人声 + BGM 混音后重新编码成 AAC。
这也是合理的。
因为 BGM 混音会改变音频轨,音频必须重新编码;
但视频画面没有变化,能 copy 就 copy,可以节省时间。
十八、当前 BGM 系统的优点
Pixelle-Video 的 BGM 系统虽然不复杂,但设计很实用。
1. 接入位置合理
BGM 在最终视频拼接后统一添加,避免每个 segment 音乐重复开始。
2. 支持无 BGM
对教程、技术讲解、严肃内容很重要。
3. 支持内置音乐
新用户不用准备素材,直接使用项目自带音乐。
4. 支持自定义音乐
用户可以把自己的音乐放进 bgm/ 或 data/bgm/,用于账号风格统一。
5. 支持 custom override
资源系统优先读取 data/bgm,再读取默认 bgm,方便 Docker 和产品化部署。
6. 支持循环播放
短视频长度不固定,loop 模式能避免音乐中途结束。
7. 音量可控
bgm_volume 可以控制背景音乐强度,默认 0.2 比较适合以旁白为主的视频。
十九、当前 BGM 系统的局限
当然,当前 BGM 系统也有一些局限。
1. BGM 不理解视频内容
目前 BGM 更像“用户选择一首音乐,然后混进去”。
它不会自动判断这条视频是励志、悬疑、温暖、科技感,还是搞笑。
2. 没有自动卡点
BGM 不会根据分镜切换点、情绪变化或结尾高潮自动调整节奏。
3. 没有自动 ducking
当人声出现时,BGM 最好自动压低;人声停顿时,BGM 可以稍微抬高。
当前逻辑主要是固定 bgm_volume 混音,还没有做人声侧链压缩或自动避让。
4. 淡出还不完整
add_bgm() 参数里有 fade_in 和 fade_out,但源码注释说明 fade_out 暂未实现,因为需要先知道视频时长,再计算淡出起点。
5. 版权问题需要用户自己注意
自定义音乐虽然方便,但音乐是否可商用、是否会被平台识别版权,仍然需要用户自己确认。
二十、GitHub Issue 中提到的第四种模式:自动生成 BGM
Pixelle-Video 目前常见模式是无 BGM、内置音乐、自定义音乐。
不过项目社区里已经有人提出“第四种模式”:根据成片自动生成 BGM。这个 issue 的思路是,在视频合成完成后,把成片交给配乐模型,根据视频节奏和情绪自动生成原创背景音乐,再通过 ffmpeg 混音。
这个建议很有意思。
因为它刚好补上了当前 BGM 系统的一个短板:
当前:
用户选音乐,音乐不理解视频内容。
自动生成 BGM:
根据成片生成音乐,音乐更贴合视频节奏和情绪。
如果未来实现,可以形成四种 BGM 模式:
none:
不加 BGM。
builtin:
使用内置音乐。
custom:
使用用户上传音乐。
generated:
根据最终视频自动生成 BGM。
从 Pixelle-Video 现有架构看,这个扩展点也比较自然,因为当前系统已经有了:
final_no_bgm.mp4
↓
_add_bgm_to_video()
↓
final.mp4
只要在中间插入一步:
final_no_bgm.mp4
↓
BGM generation API
↓
generated_bgm.mp3
↓
_add_bgm_to_video()
↓
final.mp4
就能比较顺地接入。
二十一、二次开发:如何让 BGM 更智能?
如果基于 Pixelle-Video 继续开发,BGM 系统有不少增强空间。
1. 增加 BGM 分类
可以把音乐按情绪分类:
warm
sad
epic
calm
funny
tech
suspense
inspiring
用户选择视频类型后,系统自动推荐音乐。
2. 增加自动 ducking
当 TTS 人声出现时,自动降低 BGM:
人声开始:
BGM 降低到 15%
人声停顿:
BGM 回升到 25%
这样能兼顾氛围和清晰度。
3. 增加结尾淡出
可以先读取最终视频时长,再计算 fade_out 起点:
video_duration = 45s
fade_out = 3s
fade_out_start = 42s
然后对 BGM 应用淡出滤镜。
4. 增加 BGM 预处理
自定义音乐可能有音量过大、前奏太长、格式不兼容等问题。
可以自动处理:
转码为统一格式
裁剪前奏
音量标准化
循环点优化
响度检测
5. 增加按分镜情绪配乐
更高级的做法是根据每个 frame 的 narration 判断情绪,然后动态切换 BGM 或调整音量。
例如:
开头悬念:
suspense
中间解释:
calm
结尾鼓励:
inspiring
不过这会明显增加合成复杂度。
6. 增加自动生成 BGM
参考社区 issue 的方向,可以在 final_no_bgm.mp4 生成后调用配乐模型生成一条匹配视频的 BGM,再混入最终视频。
这会让 Pixelle-Video 从“选择音乐”升级为“自动配乐”。
二十二、常见问题排查
1. 选择了 BGM,但最终视频没有音乐
优先检查:
bgm_path 是否为空
BGM 文件是否存在
文件是否放在 bgm/ 或 data/bgm/
文件扩展名是否是支持的音频格式
ffmpeg 是否能读取该音频文件
_resolve_bgm_path() 找不到文件时会抛出错误,并列出尝试过的路径和可用 BGM 文件。
2. 自定义音乐不显示
检查:
是否放到了正确目录
Docker 下是否放在 ./data/bgm/
文件扩展名是否是 mp3 / wav / ogg / flac / m4a / aac
是否和默认文件重名
资源系统会合并默认目录和 data/bgm,并对同名文件使用自定义版本。
3. BGM 太大,盖住人声
降低:
bgm_volume
默认是 0.2,如果仍然太大,可以调到:
0.1
0.05
4. BGM 播一半没了
检查 bgm_mode。
如果是 once,音乐只播放一次。
如果希望全程都有音乐,应使用:
bgm_mode = loop
5. BGM 循环点很突兀
这是音乐素材本身的问题。
解决方式:
换一首更适合循环的音乐
提前剪辑成无缝循环版本
使用更长的 BGM
后续增加 crossfade loop
6. 添加 BGM 时报 ffmpeg 错误
可能是:
ffmpeg 没安装
音频格式不兼容
BGM 文件损坏
路径中有特殊字符
视频原音轨异常
VideoService 在执行视频处理前会检查系统是否安装了 ffmpeg,找不到会抛出安装提示。
二十三、源码阅读建议
如果你要阅读 Pixelle-Video 的 BGM 相关源码,建议按这个顺序:
1. README.md
看 WebUI 中 BGM 的三种模式:无 BGM、内置音乐、自定义音乐。
2. pixelle_video/pipelines/standard.py
看 post_production() 如何把 bgm_path、bgm_volume、bgm_mode 传给 concat_videos()。
3. pixelle_video/services/video.py
看 concat_videos() 如何先拼接 segment,再调用 _add_bgm_to_video()。
4. pixelle_video/services/video.py
看 _resolve_bgm_path() 如何解析直接路径、data/bgm 和默认 bgm 目录。
5. pixelle_video/services/video.py
看 add_bgm() 如何用 ffmpeg 的 volume 和 amix 混合人声与 BGM。
6. pixelle_video/utils/os_util.py
看资源系统如何支持 data/bgm 覆盖默认 bgm。
7. docker-compose.yml
如果用 Docker,看 ./data 如何挂载到 /app/data,保证自定义 BGM 持久化。
这条路线可以完整串起:
用户选择 BGM
↓
bgm_path / bgm_volume / bgm_mode
↓
post_production()
↓
concat_videos()
↓
_resolve_bgm_path()
↓
add_bgm()
↓
final.mp4
二十四、总结
这一篇我们分析了 Pixelle-Video 的背景音乐系统。
它的核心链路是:
所有 frame 生成 segment
↓
StandardPipeline.post_production()
↓
收集 frame.video_segment_path
↓
VideoService.concat_videos()
↓
如果没有 bgm_path:
直接拼接成 final.mp4
如果有 bgm_path:
先拼接成 final_no_bgm.mp4
再解析 BGM 路径
再用 ffmpeg 混合原视频人声和 BGM
输出 final.mp4
从设计上看,Pixelle-Video 的 BGM 系统有几个关键点:
BGM 在最终成片阶段统一添加。
TTS 人声是主音轨,BGM 是辅助氛围。
bgm_path 为空时不加 BGM。
内置音乐和自定义音乐最后都会解析成真实文件路径。
data/bgm 优先级高于默认 bgm,适合自定义和 Docker 部署。
bgm_volume 控制背景音乐音量。
bgm_mode 控制音乐播放一次还是循环。
ffmpeg 的 amix 负责把人声和背景音乐混合。
一句话总结:
Pixelle-Video 的 BGM 系统,本质是在所有视频片段拼接完成后,把内置或自定义音乐解析成真实音频路径,再通过 ffmpeg 将其以指定音量和循环模式混入最终视频的人声轨道中。
528

被折叠的 条评论
为什么被折叠?



