音频处理与音视频融合接口设计文档
- -音频处理与音视频融合接口设计文档
文档信息
| 项目 | 内容 |
|---|---|
| 标题 | /api/audio/process/ 音频处理与音视频融合接口设计文档 |
| 版本 | v1.0 |
| 作者 | - |
| 日期 | 2024-12-24 |
| 适用范围 | TransDubPlatform 译配平台 - 音频处理模块 |
目录
- 1. 背景与现状
- 2. 目标与非目标
- 3. 术语表与关键实体
- 4. 系统上下文
- 5. 容器与组件视图
- 6. 核心数据流与控制流
- 7. API与接口设计
- 8. 数据存储设计
- 9. 关键算法与业务规则
- 10. 质量属性与横切关注点
- 11. 部署与运维
- 12. 测试策略
- 13. 方案对比与取舍
- 14. 风险清单与缓解措施
- 15. 未决问题与需补充材料
- 16. 附录
1. 背景与现状
1.1 业务背景
TransDubPlatform(译配平台)是一个视频翻译配音平台,核心业务流程包括:
- 视频上传与音频提取
- 语音分离(人声/背景音分离)
- 语音识别(ASR)生成台本
- 台本翻译
- AI配音(TTS)与音频合并
- 音视频融合输出
本文档聚焦于 /api/audio/process/{dubDetailId} 接口,该接口负责:
- 将多段TTS生成的配音音频按时间轴合并为完整音轨
- 将合并后的人声配音与背景音、原视频进行融合
- 输出最终的配音视频文件
依据: transdubplatform-service/.../AudioController.java
1.2 技术背景
| 技术栈 | 说明 | 依据 |
|---|---|---|
| 语言/框架 | Java 8 + Spring Boot | Dockerfile, build.gradle |
| 音视频处理 | FFmpeg (内嵌于JAR包) | Dockerfile, FfmpegInitializer.java |
| 对象存储 | 阿里云OSS | OSSService.java, application.yml |
| 数据库 | MySQL | application.yml (druid配置) |
| 缓存 | Redis | application.yml |
1.3 当前痛点与约束
| 痛点/约束 | 说明 | 依据 |
|---|---|---|
| 性能瓶颈 | 大量音频片段顺序合并耗时长 | AudioSilenceAdder.java 采用归并树优化 |
| 视频重编码耗时 | 原方案需重新编码视频流 | VideoAudioMergeService.java 使用 -c:v copy 优化 |
| 背景音可选 | 部分场景无背景音,需兼容处理 | 新增 checkBackgroundAudioExists() 方法 |
| 临时文件管理 | 大量临时文件需及时清理 | cleanupTempDirectory() 方法 |
2. 目标与非目标
2.1 目标(Goals)
| 目标 | 衡量指标/验收方式 |
|---|---|
| G1: 支持多段音频按时间轴精确合并 | 输出音频与原视频时间轴对齐,误差 < 50ms |
| G2: 支持有/无背景音两种融合模式 | 背景音不存在时自动切换为纯人声替换模式 |
| G3: 视频流零重编码 | FFmpeg命令使用 -c:v copy,处理速度提升10倍以上 |
| G4: 并行处理优化 | 文件下载并行化,音频合并采用归并树并行 |
| G5: 输出MP4格式视频 | 输出文件可直接播放,支持流媒体快速启动 |
2.2 非目标(Non-Goals)
| 非目标 | 说明 |
|---|---|
| NG1: 视频转码/分辨率调整 | 本接口不处理视频画面,仅处理音轨 |
| NG2: 实时流处理 | 本接口为批处理模式,不支持实时流 |
| NG3: 多语言音轨 | 当前仅支持单一目标语言音轨输出 |
3. 术语表与关键实体
3.1 术语表
| 术语 | 定义 |
|---|---|
| dubDetailId | 配音详情ID,关联 program_dub_detail 表主键 |
| partNumber | 视频片段编号,一个视频可切分为多个片段 |
| TTS | Text-to-Speech,文本转语音服务(使用ElevenLabs) |
| 背景音(International Audio) | 从原视频分离出的非人声音轨(音乐、环境音等) |
| 纯人声(Pure Voice) | TTS生成的配音人声音轨 |
| 音频合并 | 将多段TTS音频按时间偏移量拼接为完整音轨 |
| 音视频融合 | 将音轨与视频流合并为最终视频文件 |
| adelay | FFmpeg音频延迟滤镜,用于时间轴对齐 |
| amix | FFmpeg音频混合滤镜,用于多音轨混合 |
3.2 关键实体
| 实体 | 说明 | 依据 |
|---|---|---|
ProgramDubDetail | 配音详情实体,记录配音任务状态 | ProgramDubDetail.java |
DubAudioInfo | 配音音频信息,记录每段TTS音频的时间和路径 | DubAudioInfo.java |
DubInfoParams | 配音信息参数,包含视频/背景音/人声路径 | DubInfoParams.java |
VideoAudioMergeRequest | 音视频融合请求DTO | VideoAudioMergeRequest.java |
VideoAudioMergeResponse | 音视频融合响应DTO | VideoAudioMergeResponse.java |
4. 系统上下文(C4: Context)
4.1 系统边界与外部依赖
这张图回答:音频处理模块与哪些外部系统交互?
/api/audio/process/"] end subgraph ExternalSystems["外部系统"] OSS["阿里云OSS
对象存储"] MySQL["MySQL
业务数据库"] Redis["Redis
缓存/进度"] ElevenLabs["ElevenLabs
TTS服务"] end subgraph Infrastructure["基础设施"] FFmpeg["FFmpeg
音视频处理引擎"] end FE -->|"HTTP POST"| AudioAPI API -->|"HTTP POST"| AudioAPI AudioAPI -->|"下载/上传文件"| OSS AudioAPI -->|"读写配音数据"| MySQL AudioAPI -->|"进度缓存"| Redis AudioAPI -->|"调用TTS"| ElevenLabs AudioAPI -->|"音视频处理命令"| FFmpeg
4.2 信任边界
| 边界 | 信任级别 | 说明 |
|---|---|---|
| 前端 → API | 需认证 | 通过Token认证(依据: application.yml token配置) |
| API → OSS | 内部信任 | 使用AK/SK认证 |
| API → MySQL | 内部信任 | 内网访问 |
| API → FFmpeg | 完全信任 | 本地进程调用 |
5. 容器与组件视图(C4: Container + Component)
5.1 服务/模块清单
| 模块 | 职责 | 运行方式 | 依据 |
|---|---|---|---|
transdubplatform-service | Web服务主模块,提供REST API | Spring Boot JAR | Dockerfile |
TransDubPlatform-system | 业务逻辑模块,包含音频处理核心服务 | 依赖库 | build.gradle |
TransDubPlatform-common | 公共工具模块 | 依赖库 | settings.gradle |
5.2 组件映射表
这张图回答:音频处理涉及哪些核心组件及其依赖关系?
/api/audio/*"] end subgraph Service["Service层"] PTS["ProgramTtsServiceImpl
TTS配音服务"] ASA["AudioSilenceAdder
音频合并服务"] VAMS["VideoAudioMergeService
音视频融合服务"] AS["AudioService
音频信息服务"] end subgraph Infrastructure["基础设施层"] OSS["OSSService
对象存储服务"] FFI["FfmpegInitializer
FFmpeg初始化"] end subgraph Repository["数据访问层"] DAIR["DubAudioInfoRepository"] PDDR["ProgramDubDetailRepository"] end AC --> PTS AC --> VAMS PTS --> ASA ASA --> VAMS ASA --> AS ASA --> OSS VAMS --> OSS VAMS --> FFI ASA --> FFI AS --> DAIR ASA --> PDDR
5.3 目录到组件映射
| 目录路径 | 组件 | 职责 | 入口文件 |
|---|---|---|---|
transdubplatform-service/.../controller/business/ | Controller | REST API入口 | AudioController.java |
TransDubPlatform-system/.../service/impl/ | Service | 业务逻辑 | AudioSilenceAdder.java, VideoAudioMergeService.java |
TransDubPlatform-system/.../service/oss/ | OSS服务 | 文件存储 | OSSService.java |
TransDubPlatform-system/.../service/utils/ | 工具类 | FFmpeg封装 | FfmpegInitializer.java |
TransDubPlatform-system/.../domain/ | 实体/DTO | 数据模型 | DubAudioInfo.java |
TransDubPlatform-system/.../mapper/ | Repository | 数据访问 | DubAudioInfoRepository.java |
6. 核心数据流与控制流
6.1 链路1:音频处理主流程(/api/audio/process/ {dubDetailId})
这张图回答:音频处理接口的完整调用链路是什么?
6.1.1 时序图
6.1.2 数据流图
这张图回答:数据在各存储系统间如何流转?
(OSS)"] VIDEO["原视频文件
(OSS)"] BG_AUDIO["背景音文件
(OSS)"] end subgraph Process["处理过程"] LOCAL_TEMP["本地临时目录
/opt/startimes/service/temp/"] FFMPEG["FFmpeg处理"] end subgraph Output["输出数据"] MERGED_AUDIO["合并音频
(OSS)"] FINAL_VIDEO["融合视频
(OSS)"] end subgraph DB["数据库"] DUB_AUDIO_INFO["dub_audio_info
(读取)"] PROGRAM_DUB_DETAIL["program_dub_detail
(读写)"] end DUB_AUDIO_INFO -->|"音频路径列表"| TTS_FILES TTS_FILES -->|"下载"| LOCAL_TEMP VIDEO -->|"下载"| LOCAL_TEMP BG_AUDIO -->|"下载(可选)"| LOCAL_TEMP LOCAL_TEMP -->|"音频合并"| FFMPEG FFMPEG -->|"输出"| LOCAL_TEMP LOCAL_TEMP -->|"上传"| MERGED_AUDIO LOCAL_TEMP -->|"上传"| FINAL_VIDEO FINAL_VIDEO -->|"更新videoFilePath"| PROGRAM_DUB_DETAIL
6.1.3 关键数据结构
DubAudioInfo(音频片段信息)
// 依据: DubAudioInfo.java
{
"id": 12345,
"orderNumber": 0, // 序号,用于排序
"programDubDetailId": 100, // 关联配音详情ID
"startTime": "00:00:05,200", // 开始时间 HH:mm:ss,SSS
"endTime": "00:00:08,500", // 结束时间
"audioPath": "/opt/.../0.mp3", // 本地音频路径
"deleteFlag": 1 // 删除标识
}
VideoAudioMergeRequest(融合请求)
// 依据: VideoAudioMergeRequest.java
{
"videoPath": "/path/to/video.mp4", // OSS视频路径
"backgroundAudioPath": "/path/to/bg.mp3", // OSS背景音路径(可选)
"voiceAudioPath": "/path/to/voice.mp3", // OSS人声路径
"outputFileName": "output.mp4", // 输出文件名(可选)
"outputFilePath": "/output/path/" // 输出目录
}
6.2 链路2:音频归并合并流程
这张图回答:大量音频片段如何高效合并?
6.2.1 时序图
6.2.2 归并树示意
输入: 25个音频片段
Level 0: [1-10] [11-20] [21-25] <- 3批并行
↓ ↓ ↓
Level 1: [A] [B] [C] <- 3个中间文件
↓ ↓ ↓
Level 2: [Final] <- 最终输出
6.3 链路3:音视频融合流程(有/无背景音)
这张图回答:两种融合模式的处理差异是什么?
ossService.exitObject()"} CheckBG -->|"存在"| HasBG["有背景音模式"] CheckBG -->|"不存在/为空"| NoBG["无背景音模式"] subgraph HasBG_Flow["有背景音流程"] HasBG --> Download3["并行下载3个文件
视频+背景音+人声"] Download3 --> FFmpeg_Mix["FFmpeg amix混合
[1:a][2:a]amix=inputs=2"] FFmpeg_Mix --> Map_Mix["映射: 0:v + [aout]"] end subgraph NoBG_Flow["无背景音流程"] NoBG --> Download2["并行下载2个文件
视频+人声"] Download2 --> FFmpeg_Replace["FFmpeg直接映射
-map 0:v -map 1:a"] FFmpeg_Replace --> Map_Replace["映射: 0:v + 1:a"] end Map_Mix --> Encode["音频编码
AAC 96k 22050Hz"] Map_Replace --> Encode Encode --> VideoCopy["视频流复制
-c:v copy"] VideoCopy --> Output["输出MP4
+faststart"] Output --> Upload["上传OSS"] Upload --> End["完成"]
7. API与接口设计
7.1 对外API
7.1.1 POST /api/audio/process/ {dubDetailId}
| 属性 | 值 |
|---|---|
| 端点 | /api/audio/process/{dubDetailId} |
| 方法 | POST |
| 描述 | 处理配音音频:合并TTS音频片段 + 音视频融合 |
| 依据 | AudioController.java |
路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| dubDetailId | Long | 是 | 配音详情ID |
请求体
{
"partNumber": 1 // 片段编号
}
| 字段 | 类型 | 必填 | 说明 | 依据 |
|---|---|---|---|---|
| partNumber | Integer | 是 | 视频片段编号 | FFmpegProcessAudioParams.java |
响应
| 状态码 | 说明 |
|---|---|
| 200 | 处理成功(异步处理,立即返回) |
| 500 | 处理失败 |
鉴权: 需要Token认证(依据: application.yml token配置)
幂等性: 非幂等,重复调用会重新处理
7.1.2 POST /api/audio/merge
| 属性 | 值 |
|---|---|
| 端点 | /api/audio/merge |
| 方法 | POST |
| 描述 | 视频音频融合:将背景音和人声融合到视频中 |
| 依据 | AudioController.java |
请求体
{
"videoPath": "/path/to/video.mp4",
"backgroundAudioPath": "/path/to/background.mp3",
"voiceAudioPath": "/path/to/voice.mp3",
"outputFileName": "output.mp4",
"outputFilePath": "/output/path/"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| videoPath | String | 是 | OSS视频文件路径 |
| backgroundAudioPath | String | 否 | OSS背景音文件路径(不存在则使用纯人声模式) |
| voiceAudioPath | String | 是 | OSS人声配音文件路径 |
| outputFileName | String | 否 | 输出文件名 |
| outputFilePath | String | 是 | 输出目录路径 |
响应体
{
"success": true,
"outputOssPath": "/output/path/output.mp4",
"outputSignedUrl": "https://oss.../output.mp4?sign=...",
"costTimeMs": 12500,
"errorMessage": null
}
| 字段 | 类型 | 说明 |
|---|---|---|
| success | boolean | 是否成功 |
| outputOssPath | String | 输出文件OSS路径 |
| outputSignedUrl | String | 带签名的下载URL(1小时有效) |
| costTimeMs | long | 处理耗时(毫秒) |
| errorMessage | String | 错误信息(失败时) |
错误码
| 错误信息 | 说明 |
|---|---|
| 请求参数不能为空 | request为null |
| 视频文件路径不能为空 | videoPath为空 |
| 配音人声文件路径不能为空 | voiceAudioPath为空 |
| 融合处理失败: xxx | FFmpeg执行失败 |
7.2 内部接口
7.2.1 AudioSilenceAdder.processDubbingAudio()
// 依据: AudioSilenceAdder.java
public String processDubbingAudio(Long dubDetailId, FFmpegProcessAudioParams params)
| 参数 | 类型 | 说明 |
|---|---|---|
| dubDetailId | Long | 配音详情ID |
| params | FFmpegProcessAudioParams | 包含partNumber |
| 返回值 | String | 合并后音频的OSS路径,失败返回null |
7.2.2 VideoAudioMergeService.mergeVideoAudio()
// 依据: VideoAudioMergeService.java
public VideoAudioMergeResponse mergeVideoAudio(VideoAudioMergeRequest request)
| 参数 | 类型 | 说明 |
|---|---|---|
| request | VideoAudioMergeRequest | 融合请求参数 |
| 返回值 | VideoAudioMergeResponse | 融合结果 |
7.2.3 OSSService.exitObject()
// 依据: OSSService.java
public Boolean exitObject(String objectName)
| 参数 | 类型 | 说明 |
|---|---|---|
| objectName | String | OSS对象路径 |
| 返回值 | Boolean | 文件是否存在 |
8. 数据存储设计
8.1 数据库表
8.1.1 dub_audio_info(配音音频信息表)
依据: V1.2.2_20250616__DB_init.sql
CREATE TABLE `dub_audio_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`order_number` int(11) NOT NULL COMMENT '序号',
`fk_program_dub_detail_id` bigint(20) NOT NULL COMMENT '配音详细id',
`start_time` varchar(255) NOT NULL COMMENT '开始时间',
`end_time` varchar(255) NOT NULL COMMENT '结束时间',
`audio_path` varchar(1024) NOT NULL COMMENT '音频文件路径',
`delete_flag` tinyint(4) NOT NULL DEFAULT '1' COMMENT '删除标识',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='配音输出音频信息表';
| 字段 | 类型 | 索引 | 说明 |
|---|---|---|---|
| id | bigint | PK | 主键 |
| order_number | int | - | 序号,用于排序 |
| fk_program_dub_detail_id | bigint | 建议添加索引 | 关联配音详情 |
| start_time | varchar(255) | - | 格式: HH:mm:ss,SSS |
| end_time | varchar(255) | - | 格式: HH:mm:ss,SSS |
| audio_path | varchar(1024) | - | 本地文件路径 |
| delete_flag | tinyint | - | 0已删除/1未删除 |
8.1.2 program_dub_detail(配音详情表)
依据: V1.1.0_20250328__DB_init.sql
CREATE TABLE `program_dub_detail` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`fk_program_process_detail_id` bigint(20) NOT NULL COMMENT '详单id',
`part_number` int(11) NOT NULL COMMENT '片段编号',
`delete_flag` tinyint(4) NOT NULL DEFAULT 1,
`start_time` timestamp NULL,
`completed_time` timestamp NULL,
`status` tinyint(4) NOT NULL COMMENT '状态',
`audio_file_path` varchar(1024) COMMENT '音频文件路径',
`video_file_path` varchar(1024) COMMENT '视频文件路径',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='配音详表';
| 字段 | 类型 | 说明 |
|---|---|---|
| audio_file_path | varchar(1024) | 合并后音频OSS路径 |
| video_file_path | varchar(1024) | 融合后视频OSS路径 |
8.2 文件存储(OSS)
| 文件类型 | 路径模式 | 说明 |
|---|---|---|
| TTS音频片段 | /opt/startimes/service/{dubDetailId}/{lang}/{episode}/DUB/{partNumber}/{lineNo}.mp3 | 本地临时存储 |
| 合并音频 | /{programContentId}/{lang}/{episode}/DUB/{partNumber}/complete_audio_with_silence.mp3 | OSS存储 |
| 融合视频 | /{path}/merged/{filename}_merged.mp4 | OSS存储 |
| 背景音 | 由上游提供 | OSS存储 |
| 原视频 | 由上游提供 | OSS存储 |
8.3 临时文件
| 目录 | 用途 | 清理策略 |
|---|---|---|
/opt/startimes/service/temp/merge/{jobId}/ | 音视频融合临时文件 | 任务完成后立即清理 |
/opt/startimes/service/temp/{dubDetailId}/{partNumber}/ | 音频合并临时文件 | 任务完成后立即清理 |
/opt/startimes/service/temp/merge/output/{jobId}/ | 融合输出临时文件 | 上传OSS后清理 |
8.4 缓存(Redis)
| Key模式 | 用途 | TTL | 依据 |
|---|---|---|---|
program:tts:progress:{dubDetailId} | TTS进度缓存 | 1天 | ProgramTtsServiceImpl.java |
9. 关键算法与业务规则
9.1 音频时间轴对齐算法
依据: AudioSilenceAdder.java
输入: List<DubAudioInfo> 包含 startTime, endTime, audioPath
输出: 按时间轴对齐的完整音频
算法:
1. 解析时间字符串为毫秒: "HH:mm:ss,SSS" -> milliseconds
2. 计算全局最小起始时间: globalMinStartTime = min(all startTime)
3. 对每个音频片段计算相对延迟: relativeDelay = startTime - globalMinStartTime
4. 使用FFmpeg adelay滤镜添加延迟: adelay={relativeDelay}:all=1
5. 使用amix滤镜混合所有音频流
9.2 归并树合并算法
依据: AudioSilenceAdder.mergeAudioClipsWithTree()
输入: N个音频片段
参数: MERGE_BATCH_SIZE = 10
算法:
1. 如果N=1,直接处理单个片段返回
2. 将N个片段分成 ceil(N/10) 个批次
3. 并行处理每个批次:
- 计算批次内最小起始时间
- 使用amix合并批次内所有音频
- 输出中间文件,记录绝对起始时间
4. 收集所有中间文件作为下一层输入
5. 重复步骤2-4直到只剩1个文件
6. 最终层应用volume=10增益
复杂度: O(N) 音频处理,O(log N) 层级
9.3 背景音存在性判断规则
依据: VideoAudioMergeService.checkBackgroundAudioExists()
规则:
1. 如果 backgroundAudioPath 为空或空白 -> 无背景音模式
2. 如果 ossService.exitObject(backgroundAudioPath) 返回false -> 无背景音模式
3. 如果检查过程发生异常 -> 无背景音模式(降级处理)
4. 其他情况 -> 有背景音模式
9.4 FFmpeg命令构建规则
有背景音模式:
ffmpeg -y -threads 0 \
-i {video} -i {background} -i {voice} \
-filter_complex "[1:a][2:a]amix=inputs=2:duration=longest:normalize=0[aout]" \
-map 0:v -map [aout] \
-c:v copy -c:a aac -b:a 96k -ar 22050 -ac 1 \
-shortest -movflags +faststart \
{output}
无背景音模式:
ffmpeg -y -threads 0 \
-i {video} -i {voice} \
-map 0:v -map 1:a \
-c:v copy -c:a aac -b:a 96k -ar 22050 -ac 1 \
-shortest -movflags +faststart \
{output}
10. 质量属性与横切关注点
10.1 性能与容量
| 指标 | 当前值/策略 | 依据 |
|---|---|---|
| FFmpeg超时 | 600秒 | FFMPEG_TIMEOUT_SECONDS |
| FFprobe超时 | 30秒 | FFPROBE_TIMEOUT_SECONDS |
| 下载线程池 | CPU核心数×2(最小4) | downloadExecutor |
| 音频合并线程池 | CPU核心数 | executorService |
| 归并批次大小 | 10个/批 | MERGE_BATCH_SIZE |
| 音频采样率 | 22050 Hz | SAMPLE_RATE |
| 音频比特率 | 32k (合并) / 96k (融合) | AUDIO_BITRATE |
瓶颈点:
- OSS文件下载(已通过并行下载优化)
- FFmpeg音频编码(已通过低质量参数优化)
- 大量音频片段合并(已通过归并树优化)
10.2 可靠性
| 机制 | 实现方式 | 依据 |
|---|---|---|
| 超时控制 | process.waitFor(timeout, TimeUnit.SECONDS) | VideoAudioMergeService.java |
| 进程强制终止 | process.destroyForcibly() | 超时后执行 |
| 输出文件验证 | 检查文件存在性和大小 | executeFfmpegMerge() |
| 异常降级 | 背景音检查失败时降级为纯人声模式 | checkBackgroundAudioExists() |
| 资源清理 | finally块中清理临时文件 | cleanupTempDirectory() |
10.3 可观测性
日志
| 日志级别 | 内容 | 依据 |
|---|---|---|
| INFO | 任务开始/结束、各阶段耗时、FFmpeg进度 | 各Service类 |
| WARN | 临时文件清理失败、背景音检查异常 | cleanupTempDirectory() |
| ERROR | FFmpeg执行失败、文件下载失败 | 异常处理块 |
| DEBUG | FFmpeg完整命令、FFprobe输出 | 调试信息 |
关键日志格式:
[{jobId}] 开始视频音频融合任务, 模式: {mode}, 请求参数: {request}
[{jobId}] FFmpeg命令: {command}
[{jobId}] FFmpeg进度: time={time} speed={speed}
[{jobId}] 视频音频融合任务完成,模式: {mode}, 总耗时: {cost}ms
指标(未知/需确认)
当前代码中未发现Prometheus指标埋点,但配置文件中有Prometheus端点配置:
# 依据: application.yml
management:
endpoints:
web:
exposure:
include: health,prometheus
10.4 安全
| 安全点 | 措施 | 依据 |
|---|---|---|
| API认证 | Token认证 | application.yml token配置 |
| OSS访问 | AK/SK认证,环境变量注入 | ${OSS_KEY}, ${OSS_SECRET} |
| 文件路径 | 使用UUID生成jobId,避免路径遍历 | UUID.randomUUID() |
| 临时文件 | 任务完成后立即清理 | cleanupTempDirectory() |
11. 部署与运维
11.1 部署架构
这张图回答:服务如何部署和依赖哪些基础设施?
8u212-jdk-slim"] FFmpeg["FFmpeg
/opt/startimes/service/ffmpeg/"] TempDir["临时目录
/opt/startimes/service/temp/"] end end subgraph External["外部服务"] OSS["阿里云OSS
ai-dubbing-platform-*"] MySQL["MySQL
业务数据库"] Redis["Redis
缓存服务"] end Container --> FFmpeg Container --> TempDir Container --> OSS Container --> MySQL Container --> Redis
11.2 Dockerfile分析
依据: transdubplatform-service/config/Dockerfile
FROM common-repos.startimes.me/startimes-ops/8u212-jdk-slim:latest
# FFmpeg从JAR包中提取
RUN jar xf transdubplatform-service.jar BOOT-INF/classes/static/ffmpeg ...
RUN chmod +x /opt/startimes/service/ffmpeg/ffmpeg
ENTRYPOINT java ${JAVA_OPTS} -jar /opt/startimes/service/transdubplatform-service.jar
关键点:
- 基础镜像: Java 8 (8u212)
- FFmpeg: 内嵌于JAR包,部署时提取
- 路径:
/opt/startimes/service/ffmpeg/ffmpeg
11.3 环境配置
| 环境变量 | 用途 | 依据 |
|---|---|---|
JAVA_OPTS | JVM参数 | Dockerfile |
REDIS_HOST | Redis地址 | application.yml |
OSS_KEY | OSS AccessKey | application.yml |
OSS_SECRET | OSS SecretKey | application.yml |
FTP_HOST/USER/PASS | FTP配置 | application.yml |
token_secret | Token密钥 | application.yml |
11.4 环境划分
| 环境 | 配置文件 | 依据 |
|---|---|---|
| local | config/resources/local/application.yml | 目录结构 |
| dev | config/resources/dev/application.yml | 目录结构 |
| test1 | config/resources/test1/application.yml | 目录结构 |
| production | config/resources/production/application.yml | 目录结构 |
12. 测试策略
12.1 测试层级
| 层级 | 覆盖范围 | 状态 |
|---|---|---|
| 单元测试 | Service方法 | 未知 - 未找到测试代码 |
| 集成测试 | API端到端 | 未知 |
| E2E测试 | 完整业务流程 | 未知 |
12.2 关键测试用例(建议)
| 用例ID | 场景 | 预期结果 |
|---|---|---|
| TC01 | 正常流程-有背景音 | 输出包含背景音+人声的视频 |
| TC02 | 正常流程-无背景音 | 输出仅人声的视频 |
| TC03 | 背景音路径为空 | 自动切换无背景音模式 |
| TC04 | 背景音文件不存在 | 自动切换无背景音模式 |
| TC05 | 视频文件不存在 | 返回错误信息 |
| TC06 | 人声文件不存在 | 返回错误信息 |
| TC07 | FFmpeg执行超时 | 进程被终止,返回超时错误 |
| TC08 | 大量音频片段(100+) | 归并合并成功 |
| TC09 | 单个音频片段 | 直接处理成功 |
12.3 Mock策略
| 依赖 | Mock方式 |
|---|---|
| OSSService | Mock下载/上传方法,使用本地文件 |
| FFmpeg | 使用真实FFmpeg或Mock进程输出 |
| MySQL | H2内存数据库或TestContainers |
13. 方案对比与取舍
13.1 音频合并方案
| 方案 | 优点 | 缺点 | 选择 |
|---|---|---|---|
| 方案A: 顺序合并 | 实现简单 | O(N²)复杂度,大量片段时极慢 | ❌ |
| 方案B: 归并树并行 | O(N)复杂度,并行处理 | 实现复杂,需管理中间文件 | ✅ 当前方案 |
| 方案C: 单次amix | 最简单 | FFmpeg对大量输入支持差 | ❌ |
选择理由: 归并树方案在处理大量音频片段时性能优势明显,虽然实现复杂但可维护。
13.2 音视频融合方案
| 方案 | 优点 | 缺点 | 选择 |
|---|---|---|---|
| 方案A: 视频重编码 | 兼容性好 | 极慢,CPU密集 | ❌ |
| 方案B: 视频流复制 | 极快,无质量损失 | 需要容器格式兼容 | ✅ 当前方案 |
选择理由: -c:v copy 避免视频重编码,处理速度提升10倍以上。
13.3 背景音处理方案
| 方案 | 优点 | 缺点 | 选择 |
|---|---|---|---|
| 方案A: 强制要求背景音 | 逻辑简单 | 不灵活,部分场景无背景音 | ❌ |
| 方案B: 运行时检测 | 灵活,自动适配 | 需额外OSS检查 | ✅ 当前方案 |
选择理由: 通过 ossService.exitObject() 检测背景音存在性,自动切换处理模式,向后兼容。
14. 风险清单与缓解措施
| 风险ID | 风险描述 | 影响 | 概率 | 缓解措施 |
|---|---|---|---|---|
| R01 | FFmpeg进程hang住 | 任务阻塞 | 中 | 600秒超时 + destroyForcibly |
| R02 | 临时文件未清理导致磁盘满 | 服务不可用 | 低 | finally块清理 + 定期巡检 |
| R03 | OSS下载失败 | 任务失败 | 低 | 异常捕获 + 错误日志 |
| R04 | 大量并发任务导致OOM | 服务崩溃 | 中 | 线程池限制 + JVM参数调优 |
| R05 | 音频时间轴不对齐 | 配音与画面不同步 | 低 | 毫秒级精度 + 上游已处理偏移 |
| R06 | 视频编码不兼容copy | 融合失败 | 低 | 错误日志 + 人工介入 |
15. 未决问题与需补充材料
15.1 需确认的问题
| 问题ID | 问题描述 | 需要的材料/信息 |
|---|---|---|
| Q01 | 是否有单元测试覆盖? | 测试代码目录 |
| Q02 | Prometheus指标是否已埋点? | 指标定义代码 |
| Q03 | 生产环境的JVM参数配置? | K8s deployment yaml |
| Q04 | 任务失败后的重试机制? | 重试逻辑代码 |
| Q05 | 并发任务数限制? | 限流配置 |
| Q06 | 视频格式兼容性范围? | 支持的编码格式列表 |
15.2 需补充的文件
| 文件类型 | 用途 |
|---|---|
| K8s Deployment YAML | 了解资源限制、副本数 |
| 完整的application.yml | 了解所有配置项 |
| 测试代码 | 了解测试覆盖情况 |
| CI/CD配置 | 了解发布流程 |
| 监控告警配置 | 了解可观测性 |
16. 附录
16.1 关键文件索引
| 模块 | 文件路径 | 说明 |
|---|---|---|
| Controller | transdubplatform-service/src/main/java/com/star/transdubplatform/web/controller/business/AudioController.java | API入口 |
| 音频合并 | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/service/impl/AudioSilenceAdder.java | 音频合并服务 |
| 音视频融合 | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/service/impl/VideoAudioMergeService.java | 融合服务 |
| TTS服务 | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/service/impl/ProgramTtsServiceImpl.java | TTS配音服务 |
| OSS服务 | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/service/oss/OSSService.java | 对象存储 |
| FFmpeg工具 | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/service/utils/FfmpegInitializer.java | FFmpeg初始化 |
| 音频服务 | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/service/impl/AudioService.java | 音频信息查询 |
| 请求DTO | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/domain/dto/VideoAudioMergeRequest.java | 融合请求 |
| 响应DTO | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/domain/dto/VideoAudioMergeResponse.java | 融合响应 |
| 音频实体 | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/domain/DubAudioInfo.java | 音频信息实体 |
| 配音实体 | TransDubPlatform-system/src/main/java/com/star/transdubplatform/system/domain/ProgramDubDetail.java | 配音详情实体 |
| 数据库DDL | transdubplatform-service/src/main/resources/db/migration/V1.2.2_20250616__DB_init.sql | 表结构 |
| Dockerfile | transdubplatform-service/config/Dockerfile | 部署配置 |
| 生产配置 | transdubplatform-service/config/resources/production/application.yml | 生产环境配置 |
16.2 参考
本文档所有内容均基于以下仓库文件:
- 代码文件:如上表所列
- 配置文件:
application.yml,Dockerfile - 数据库脚本:
db/migration/*.sql
文档结束