HLS 字幕与多音轨配置完全指南:WebVTT 字幕与多语言音轨实现

在国际化视频应用和在线教育场景中,多语言字幕和多音轨是提升用户体验的关键功能。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-CAPTIONS
  • GROUP-ID — 轨道组标识,同一组内的轨道可互相切换
  • NAME — 显示给用户的轨道名称
  • LANGUAGE — RFC 5646 语言代码,如 zh-CN、en、ja
  • DEFAULT — 是否为默认轨道(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 中的 AUDIOSUBTITLES 属性,它们通过 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,为全球用户提供流畅的观看体验。

测试你的 HLS 视频流

使用免费在线播放器验证字幕和多音轨配置是否正确

前往播放器 →