在国际化视频应用和在线教育场景中,多语言字幕和多音轨是提升用户体验的关键功能。HLS 协议通过 EXT-X-MEDIA 标签原生支持字幕和多音轨切换,配合 WebVTT 格式可以实现灵活的多语言流媒体方案。本文将从原理到实践,详细讲解如何配置和生成带字幕与多音轨的 M3U8 播放列表。
一、HLS 媒体轨道类型概述
HLS 协议支持四种媒体轨道类型,通过 EXT-X-MEDIA 标签声明:
- AUDIO — 音频轨道,用于多语言配音或不同音质选择
- SUBTITLES — 字幕轨道,支持 WebVTT 和 CEA-608 格式
- CLOSED-CAPTIONS — 隐藏式字幕,主要用于电视广播场景
- VIDEO — 视频轨道(较少单独使用,通常与自适应码率配合)
这些轨道通过主播放列表(Master Playlist)进行组织,播放器解析后向用户提供切换选项。
二、WebVTT 字幕格式详解
2.1 WebVTT 基础结构
WebVTT(Web Video Text Tracks)是 HLS 推荐的字幕格式,文件扩展名为 .vtt。一个基础的 WebVTT 文件结构如下:
WEBVTT
1
00:00:01.000 --> 00:00:04.000
欢迎观看 HLS 流媒体教程
2
00:00:05.000 --> 00:00:08.500
本节我们学习字幕配置方法
3
00:00:10.000 --> 00:00:15.000
字幕支持换行显示
也支持简单的样式设置
2.2 时间戳格式
时间戳格式为 HH:MM:SS.mmm(时:分:秒.毫秒),使用 --> 分隔开始和结束时间。支持行内样式设置:
00:00:01.000 --> 00:00:04.000 line:80% position:50% align:center
居中显示的字幕文本
2.3 字幕切片策略
在 HLS 中,字幕需要与视频切片对齐。通常有两种做法:
- 逐切片字幕文件:每个视频切片对应一个独立的 VTT 文件,与 TS 切片保持相同时长
- 单文件字幕:整个视频使用一个 VTT 文件,通过
EXT-X-BYTERANGE定位(较少使用)
最佳实践: 字幕切片时长应与视频切片时长完全一致,避免字幕与画面不同步。建议统一使用 10 秒切片。
三、EXT-X-MEDIA 标签语法
EXT-X-MEDIA 是 HLS 主播放列表中用于声明替代轨道的核心标签,完整语法如下:
#EXT-X-MEDIA:TYPE=AUDIO,
GROUP-ID="audio_lo",
NAME="English",
LANGUAGE="en",
DEFAULT=YES,
AUTOSELECT=YES,
URI="audio_en.m3u8"
关键属性说明:
TYPE— 轨道类型:AUDIO / SUBTITLES / CLOSED-CAPTIONSGROUP-ID— 轨道组标识,同一组内的轨道可互相切换NAME— 显示给用户的轨道名称LANGUAGE— RFC 5646 语言代码,如 zh-CN、en、jaDEFAULT— 是否为默认轨道(YES/NO)AUTOSELECT— 播放器是否可根据用户语言自动选择FORCED— 是否为强制显示字幕(仅 SUBTITLES 类型)URI— 轨道对应的 M3U8 播放列表地址
四、完整主播放列表示例
以下是一个包含多码率视频、多语言音轨和多语言字幕的完整主播放列表:
#EXTM3U
#EXT-X-VERSION:6
# 音频轨道声明
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="中文",LANGUAGE="zh-CN",DEFAULT=YES,AUTOSELECT=YES,URI="audio_zh.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="English",LANGUAGE="en",DEFAULT=NO,AUTOSELECT=YES,URI="audio_en.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="日本語",LANGUAGE="ja",DEFAULT=NO,AUTOSELECT=YES,URI="audio_ja.m3u8"
# 字幕轨道声明
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="中文",LANGUAGE="zh-CN",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,URI="subs_zh.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English",LANGUAGE="en",DEFAULT=NO,AUTOSELECT=YES,FORCED=NO,URI="subs_en.m3u8"
# 视频变体流(关联音频和字幕组)
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360,CODECS="avc1.42c01e,mp4a.40.2",AUDIO="audio",SUBTITLES="subs"
video_360p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1500000,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2",AUDIO="audio",SUBTITLES="subs"
video_720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2",AUDIO="audio",SUBTITLES="subs"
video_1080p.m3u8
注意 EXT-X-STREAM-INF 中的 AUDIO 和 SUBTITLES 属性,它们通过 GROUP-ID 将视频流与对应的音轨/字幕组关联起来。
五、使用 FFmpeg 生成多语言 M3U8
5.1 准备多语言音轨
假设你有三个独立的音频文件(中文、英文、日文)和一个视频源文件,使用 FFmpeg 一次性生成带多音轨的 HLS:
ffmpeg -i input_video.mp4 \
-i audio_zh.aac -i audio_en.aac -i audio_ja.aac \
-map 0:v -map 1:a -map 2:a -map 3:a \
-c:v libx264 -b:v 1500k -s 1280x720 \
-c:a aac -b:a 128k \
-var_stream_map "v:0,a:0 a:1 a:2" \
-master_pl_name master.m3u8 \
-f hls -hls_time 10 -hls_list_size 0 \
-hls_segment_filename "stream_%v/segment_%03d.ts" \
stream_%v/index.m3u8
5.2 添加 WebVTT 字幕
FFmpeg 也支持将字幕文件嵌入 HLS。先将 SRT 转换为 VTT:
ffmpeg -i subtitles_zh.srt subtitles_zh.vtt
ffmpeg -i subtitles_en.srt subtitles_en.vtt
然后生成字幕的 M3U8 播放列表(需要手动创建,或使用 hls_segment_type 选项):
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.000,
subs_000.vtt
#EXTINF:10.000,
subs_001.vtt
#EXTINF:10.000,
subs_002.vtt
#EXT-X-ENDLIST
注意: FFmpeg 原生对 WebVTT 字幕切片支持有限,生产环境建议使用 Bento4、Shaka Packager 等专业打包工具,它们能自动处理字幕切片与视频同步。
六、播放器端适配
6.1 hls.js 配置多语言
使用 hls.js 播放时,可以通过 API 获取和切换音轨与字幕:
const video = document.getElementById('video');
const hls = new Hls();
hls.loadSource('master.m3u8');
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function() {
// 获取所有音频轨道
console.log('音频轨道:', hls.audioTracks);
// 获取所有字幕轨道
console.log('字幕轨道:', hls.subtitleTracks);
// 切换到英文音轨(索引为1)
hls.audioTrack = 1;
// 显示英文字幕
hls.subtitleTrack = 1;
});
6.2 Safari 原生播放
Safari 浏览器原生支持 HLS 多音轨和字幕切换,用户可通过视频控件的「字幕」按钮手动选择,也可通过 JavaScript API 控制:
const video = document.querySelector('video');
// 获取可用的音轨
const audioTracks = video.audioTracks;
// 切换音轨
audioTracks[1].enabled = true;
// 获取字幕轨道
const textTracks = video.textTracks;
// 显示字幕
textTracks[0].mode = 'showing';
七、常见问题与最佳实践
7.1 字幕不同步怎么办?
确保字幕切片的时长和起始时间与视频切片完全一致。建议使用同一时间基准生成视频和字幕切片,避免累积误差。
7.2 字幕文件需要 CORS 配置吗?
需要。字幕文件与视频文件一样受浏览器同源策略限制,服务器必须配置正确的 Access-Control-Allow-Origin 响应头。
7.3 最多支持多少条轨道?
HLS 协议没有硬性限制,但建议音轨不超过 8 条、字幕不超过 16 条。过多的轨道会增加主播放列表体积,影响加载速度。
7.4 强制字幕(FORCED)的使用场景
FORCED=YES 的字幕会默认显示,即使用户没有主动开启字幕。适用于电影中外语对话的场景,只在说外语时显示字幕。
八、总结
HLS 的多音轨和字幕功能是构建国际化视频平台的基础。通过 EXT-X-MEDIA 标签组织媒体轨道,配合 WebVTT 字幕格式,可以实现灵活的多语言切换体验。实际开发中,建议使用专业的打包工具处理切片同步,并在播放器层做好语言自动检测和切换 UI,为全球用户提供流畅的观看体验。