VOD 深度剖析 第 11 部分:端到端工作流——从上传到播放
完整的 10 步 VOD 生产流水线:上传、内容审核、探测、转码、封装、发布、CDN 预热,以及使用 Step Functions 和 Temporal 进行编排、灾难恢复。
本文是 VOD 流媒体深度剖析 系列的第 11 部分。
完整流水线概览
一段视频从文件交付到全球播放,至少要经历 10 个步骤:
①Upload → ②Content Scan → ③Probe → ④Transcode → ⑤Package+Encrypt
↓ ↓ ↓ ↓ ↓
│ NSFW / copyright ffprobe Multi-rate CMAF +
│ fingerprint / resolution H.264+H.265 DRM
│ virus scan +AV1 Signing
↓
⑥Publish to Storage → ⑦Write Metadata → ⑧CDN Pre-warm → ⑨Notify → ⑩Monitor
↓ ↓ ↓ ↓ ↓
S3 / Object MySQL / ES Major region Push / QoE
Storage Index edge nodes Homepage Regression
每一步都可能失败。成熟的平台会在每个阶段都配备 重试、告警和人工兜底方案。
步骤 1:上传——把大文件送上云
挑战:
- 源文件往往有 5–50 GB(ProRes / DNxHD)
- 网络不可靠(跨境、办公室 WiFi)
- 用户可能在上传中途关闭笔记本或断网
分片上传(Multipart Upload)
把文件切分成 5–100 MB 的分片,并发上传:
Large file ────► [Chunk 1] [Chunk 2] [Chunk 3] ... [Chunk N]
│ │ │ │
▼ ▼ ▼ ▼
S3 Multipart concurrent upload (5-10 parallel)
│
▼
Merge after all complete
优势:并行加速、失败可续传(只需重试失败的分片)、S3/GCS/Azure Blob 原生支持。
去重(MD5/CRC 预校验)
上传前,客户端先计算文件的 MD5 哈希:
Client → Backend: "Uploading file, md5=abc123"
Backend → Client: "Already have it, skip upload" ← instant
or
"Not found, please upload"
S3 分片上传 API(三步)
import boto3
s3 = boto3.client('s3')
# 1. Initiate multipart upload
resp = s3.create_multipart_upload(Bucket='my-bucket', Key='video.mov')
upload_id = resp['UploadId']
# 2. Upload each part
parts = []
for i, chunk in enumerate(chunks, start=1):
resp = s3.upload_part(
Bucket='my-bucket', Key='video.mov',
UploadId=upload_id, PartNumber=i,
Body=chunk)
parts.append({'PartNumber': i, 'ETag': resp['ETag']})
# 3. Complete and merge
s3.complete_multipart_upload(
Bucket='my-bucket', Key='video.mov',
UploadId=upload_id,
MultipartUpload={'Parts': parts})
步骤 2:内容扫描——合规审核
上传的文件先进入 隔离桶(quarantine bucket)(而非生产存储)。内容必须通过审核后才能晋升到生产环境。
必要检查项
| 检查项 | 工具 |
|---|---|
| 病毒扫描 | ClamAV、VirusTotal API |
| NSFW 检测 | AWS Rekognition Content Moderation |
| 暴力 / 血腥 / 政治敏感内容 | 同上 |
| 版权指纹识别 | Audible Magic(音乐)、ACRCloud |
| 人脸识别(如有需要) | AWS Rekognition |
| 字幕合规 | 关键词过滤、区域适配 |
人工审核
AI 只是第一道过滤。高价值或处于边界的内容会进入人工审核队列:
- 审核员观看(抽样或完整观看)
- 标记为合规或不合规
- 记录判断理由
步骤 3:探测(Probe)——转码前先做校验
ffprobe 扫描文件以提取元数据:
ffprobe -v error -show_format -show_streams -of json input.mov > probe.json
可提取:分辨率、帧率、编解码器、音轨、采样率、时长、可变帧率标记、HDR 元数据。
校验规则:
- 时长 < 30 秒 → 拒绝(不是有效的剧集)
- 分辨率低于 720p → 拒绝(质量不足)
- 帧率不在 60 之内 → 告警
- 标记为 HDR 但色彩空间不是 BT.2020 → 标记待修正或拒绝
步骤 4:转码——核心生产环节
产物清单
单个源文件通常会产出:
/vod/ep-001/
mezz/original.mov ← Source backup (cold storage)
v_360p.mp4 ← H.264 360p
v_480p.mp4 ← H.264 480p
v_720p.mp4 ← H.264 720p
v_1080p.mp4 ← H.264 1080p
v_720p_hevc.mp4 ← H.265 720p
v_1080p_hevc.mp4 ← H.265 1080p
v_720p_av1.mp4 ← AV1 720p (flagship devices)
audio_en.mp4 ← English AAC
audio_zh.mp4 ← Chinese AAC
subs_en.vtt ← English subtitles
subs_zh.vtt ← Chinese subtitles
thumbnails.vtt + sprite.jpg ← Thumbnail preview (scrub bar)
并行加速
单集视频可能需要 10 多个输出档位。有两种并行策略:
按档位并行(简单):
Transcode cluster:
Worker 1: Source → 360p H.264
Worker 2: Source → 720p H.264
Worker 3: Source → 1080p H.264
Worker 4: Source → 720p H.265
...all workers run simultaneously
按 GOP 切分并行(复杂但更快):
Split source at IDR boundaries into N segments
Each segment sent to a different worker for independent transcoding
Concatenate bitstreams at the end
Netflix 和 YouTube 会启动数百台云实例并行转码一部电影,大约一小时即可完成。
转码服务选型
| 服务 | 特点 |
|---|---|
| 自建 ffmpeg 集群 | 控制力最强、大规模下成本最低、运维负担最重 |
| AWS MediaConvert | 按分钟计费、QVBR、集成 HDR/DRM |
| Bitmovin / Mux | 对开发者友好、企业级 |
成本优化
- Spot / 抢占式实例 + 检查点续跑:可省 70–80%
- 长尾内容:只做 H.264(节省转码与存储成本)
- 热门内容:追加 H.265/AV1 档位
步骤 5:封装与加密
转码后的 MP4 需要转换成流媒体格式。参见 第 5 部分(协议) 和 第 8 部分(DRM):
Transcoded MP4s
│
▼
Shaka Packager / MediaPackage / mp4box
│
▼
Output:
CMAF fMP4 segments
HLS master.m3u8 + media.m3u8
DASH manifest.mpd
(Optional) CENC/CBCS encrypted segments + license metadata
步骤 6–7:发布到存储 + 写入元数据
转码/封装后的资产上传到 生产存储(通常是一个独立的 S3“生产桶”):
/vod-production/ep-001/
init.mp4
seg_*.m4s
master.m3u8
manifest.mpd
thumbnails/...
同时写入业务数据库:
INSERT INTO episodes (
episode_id, show_id, title, duration_sec,
manifest_url, thumbnail_url,
status, publish_at, ...
) VALUES (...);
更新搜索索引(Elasticsearch / Algolia)以便被检索到。
步骤 8:CDN 预热
参见 第 7 部分:CDN 分发。
不要等第一波用户来触发回源拉取。 对新内容和预期会火的内容进行预热,把 init 分片和前 5–10 个媒体分片提前推送到全球边缘节点。
步骤 9:通知与上线
- CMS 状态从“处理中”切换为“就绪”
- 向订阅者推送通知:“你关注的剧集更新了”
- 更新首页推荐 / 排行榜
- 激活广告素材(如为商业化内容)
步骤 10:监控与回归
上线后持续监控:
- 播放成功率
- QoE 指标是否在正常区间内(参见 第 10 部分)
- 标记异常内容(例如某一集卡顿率异常偏高)
- 发现问题 → 重新转码或回滚
编排:把各步骤串联起来
上述 10 个步骤必须按顺序可靠执行,并支持 重试、并行和失败分支。这些逻辑不可能硬编码进一个脚本里。
常见编排工具
| 工具 | 特点 | 适用场景 |
|---|---|---|
| AWS Step Functions | Serverless、可视化、与 AWS 深度集成 | AWS 原生场景,AWS VOD 方案的默认选择 |
| Temporal | 分布式工作流、强一致性、类型安全 | 自管控制面 / 多云 |
| Airflow | 批量 ETL、定时任务 | 数据处理、离线分析 |
| Argo Workflows | Kubernetes 原生 | K8s 团队 |
| 自研(Kafka 驱动) | 事件驱动,每一步发布下一个事件 | 追求最大定制化 |
Step Functions 示例(简化版)
{
"StartAt": "Probe",
"States": {
"Probe": {
"Type": "Task",
"Resource": "arn:aws:lambda:...:ProbeVideo",
"Next": "ParallelTranscode"
},
"ParallelTranscode": {
"Type": "Parallel",
"Branches": [
{"StartAt": "Transcode360p", "States": {
"Transcode360p": {"Type": "Task",
"Resource": "arn:aws:mediaconvert:...", "End": true}}},
{"StartAt": "Transcode720p", "States": {
"Transcode720p": {"Type": "Task",
"Resource": "arn:aws:mediaconvert:...", "End": true}}},
{"StartAt": "Transcode1080p", "States": {
"Transcode1080p": {"Type": "Task",
"Resource": "arn:aws:mediaconvert:...", "End": true}}}
],
"Next": "Package"
},
"Package": {
"Type": "Task", "Resource": "...Package...", "Next": "Prewarm"
},
"Prewarm": {
"Type": "Task", "Resource": "...Prewarm...", "Next": "Notify"
},
"Notify": {
"Type": "Task", "Resource": "...Notify...", "End": true
}
}
}
Step Functions 内置了重试、超时、分支以及可视化的执行流程图。
灾难恢复与回滚
多区域备份
- 源文件(mezzanine 母版)通过 S3 跨区域复制(Cross-Region Replication)跨区备份
- 热门内容存储在多个区域(就近分发 + 故障转移)
回滚场景
- 新上线的内容出现问题 → 一键下架 + CDN 缓存失效
- 转码版本有 bug → 把 manifest 指针切回上一个版本
数据备份
- 元数据数据库:每日备份
- 用户观看进度(数据量大)→ 分级存储:热数据放 Redis,冷数据归档到 S3 Glacier
一个典型的时间线
一部 60 分钟的电影从上传到全球可用:
T+0min Creator uploads mezzanine to quarantine bucket
T+5min Upload complete → triggers Step Functions
T+7min NSFW + virus scan complete
T+8min ffprobe validation passes
T+10min Parallel transcode starts (H.264 x4 + H.265 x2 + AV1 x1)
T+70min All transcodes complete (~1x real-time, parallel tiers)
T+72min Packager generates HLS + DASH + DRM
T+73min Assets uploaded to production S3
T+74min CDN pre-warming complete (NA / EU / APAC)
T+75min Metadata written, search index updated, notifications sent
T+75min Live ✅
短视频/短剧应用(每集 60–90 秒)能在几分钟内跑完整条流水线。
关键要点
- VOD 流水线包含 10 个主要步骤——每一步都可能失败,都需要重试 + 告警。
- 上传:分片 + MD5 去重。存储:隔离桶 + 内容扫描。
- 转码前必须做 ffprobe 校验。
- 转码 是最耗时的步骤——按档位或 GOP 并行 + 使用 Spot 实例。
- 封装 + DRM 是发布前的最后一步。
- CDN 预热 对新内容上线至关重要。
- Step Functions / Temporal 是首选的编排工具。
- 从第一天起就要规划好 灾难恢复和回滚。
上一篇: 第 10 部分:QoE 指标
参考资料
- AWS Step Functions Developer Guide — AWS Documentation
- Temporal documentation — Temporal
- AWS Elemental MediaConvert User Guide — AWS Documentation