字幕方案
软字幕
外挂字幕
通常字幕是外挂于视频的独立字幕文件,虽然可以播放,但是我们可以轻易地删除文件来解决掉它。例如 youtube 那种字幕文件。
内挂字幕
内挂字幕/封装字幕,字幕和视频是各自独立的流,通过时间戳对齐,在播放器上挂载,并且需要播放器支持直播字幕功能。好处是可以在播放器端编程控制字幕的展示,有更多的灵活性。
软字幕相对硬字幕需要适配各个播放器,pc/h5/app 等,技术难度相对来说难度会比硬字幕大。
硬字幕
字幕本身是嵌入在视频画面中,可以烧录srt等字幕文件到视频中实现。嵌入硬字幕,已经成为视频的一部分,字幕属性不能在播放时更改,也不能隐藏和提取。
字幕文件
这些字幕的格式都可以相互转换,小象字幕 (收费软件,可以体验)
| 字幕格式 | 简介 | 样式 |
|---|---|---|
| Srt | 一句时间代码 + 一句字幕 | |
| Webvtt | HTML5中的 元素来标记额外的文本轨道资源,vtt结尾文件 | |
| Stl | 类似CSV | |
| Sbv | Youtube的字幕格式 | |
| Ass | 实现比传统字幕诸如srt等格式更为复杂的功能 | |
| Dfxp | Netflix只支持DFXP字幕格式 | |
| Ttml | 基于文本字幕标准的工作让更多数字媒体内容提高了无障碍访问能力 |
Webvtt 字幕
H5 Video 加载外挂字幕一般使用的是 vtt 格式,那么使用srt格式是否可行,测试结果是不可以。 视频文件和字幕文件是各自独立的,也就是字幕可以跟视频完全不相关。
# 测试代码 source,track都输入远程地址
# 本地文件打开,使用以下代码https加载远程连接做测试,需要crossorigin 为了防止跨域请求报错,source、track请求资源遵守浏览器的规则,不像img src一样可以加载任意源
<video controls crossorigin="anonymous">
<source src="https://${地址}/test.mp4" type="video/mp4" />
<track src="https://${地址}/test.vtt" kind="subtitles" label="中文字幕" srclang="zh" default />
</video>
Srt 字幕
一般处理硬字幕用srt格式。
# test.srt 字幕文件
1
00:00:00,000 --> 00:00:04,280
下面给家里养狗狗的小伙伴推荐一款
可爱爆棚的变身外衣
2
00:00:04,480 --> 00:00:06,280
尤其适合养小型犬的朋友
# 字幕文件为 test.srt
ffmpeg -i test.mp4 -vf subtitles=test.srt new_test.mp4
# 可以为字幕定制字体样式
ffmpeg -i test.mp4 -filter_complex "subtitles=test.srt:force_style='FontName=DejaVu Serif,PrimaryColour=&HAA00FF00,boxcolor=&HAA00FF00'" -c:a copy new_test.mp4
嵌入软字幕
ffmpeg -i input.mkv -i subtitles.ass -codec copy -map 0 -map 1 output.mkv
ffmpeg -i infile.mp4(输入文件名) -f srt -i infile.srt(嵌入前的字幕地址) -c:v copy -c:a copy -c:s mov_text(嵌入后的字幕名称) outfile.mp4(输出文件名)
字幕提取
1、查看视频信息确定是否有字幕
ffmpeg -i xxx.mp4
如果视频中只看到视频流和音频流,那么是无法提取出字幕的。这种一般需要对语音识别然后转字幕。也就意味着硬字幕后无法再提取出来。
如果视频中有字幕流,则可以提取出来。
2、提取软字幕
ffmpeg -i video_file.mp4 -map 0:s:0 subtitle.srt
- -map 0:s:0 subtitle.srt
- -map:高级参数
- 0:s:0
- 0 -> input_file_id=文件id,输入的文件索引编号,此处就一个文件,所以0表示此处输入的mp4视频:video_file.mp4
- :s -> :stream_specifier, 流stream选择的是字幕subtitle
- :0 -> :stream_specifier 第0个字幕,此处只有一个字幕,就是这个唯一的字幕
字幕格式转换
# ffmpeg 一句命令就可以实现。不仅限于以下2种,其他格式都可以尝试一下。
ffmpeg -i 字幕.srt 字幕.ass
ffmpeg -i 字幕.srt 字幕.vtt
以上都是有格式的字幕见转换,如果是没有格式的txt文件和srt字幕转换会有点麻烦。
Srt格式转为Txt文件(删除时间码)
SRT字幕文件,删除里面的时间码,保留其中的文字部分保存为Txt文件即可。
Txt文件转为Srt格式(手动打标)
Txt文件转为Srt格式相对麻烦,Txt相对Srt格式缺少了时间戳,文字和时间需要手动对齐。如下字幕编辑器
直播中实时字幕实现
webvtt字幕只能适用于普通的视频字幕。对于直播,生产端要能实时生成字幕内容,并且播放端要不停的获取字幕内容来显示。能满足不断生成内容,不断获取内容的方式,只有流式数据。例如直播中音视频数据采用了直播流协议RTMP,FLV和HLS。因此字幕也需要定义这样的一个协议,我们叫做字幕流协议。
HLS协议
HLS协议原理就是把视频切分成一个个小的视频切片(.ts 文件)。把最新的切片地址放到一个索引文本文件(.m3u8)中,然后浏览器不断地获取索引文件,就可以得到最新的切片地址,进而获取切片视频内容,来播放视频。
1、视频流索引文件格式如下,里面主要就是切片文件的地址列表:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:224
#EXT-X-TARGETDURATION:5
#EXTINF:5.000,
75118df9-95f2-46a1-946d-d1ba57b3b5ac/1553772845_224.ts
#EXTINF:5.000,
75118df9-95f2-46a1-946d-d1ba57b3b5ac/1553772855_225.ts
- EXTM3U: 这个是M3U8文件必须包含的标签,必须放在第一行
- EXT-X-VERSION:M3U8文件的版本,常见的是3(目前最高版本应该是7)
- EXT-X-MEDIA-SEQUENCE: 第一个TS分片的序列号
- EXT-X-TARGETDURATION: 每个分片TS的最大的时长
- EXT-X-ALLOW-CACHE: 是否允许cache
- EXT-X-ENDLIST: m3u8文件结束符,表明M3U8文件不会再产生更多的切片
- EXTINF extra info:分片TS的信息,如时长,带宽等
2、字幕流原理是一样的,我们也采用HLS协议。
字幕流的索引文件(.m3u8)内容如下,这里的切片换成了WebVtt(.vtt) 文件。
#EXTM3U
#EXT-X-TARGETDURATION:15
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:411
#EXTINF:1.08,
413000_cn.vtt
#EXTINF:5.94,
414000_cn.vtt
#EXTINF:2.37,
415000_cn.vtt
#EXTINF:5.82,
合并音视频流索引文件和字幕流索引文件
通过上述方法,我们得到了2个索引文件:
- 音视频索引文件(.m3u8)
- 字幕流索引文件(.m3u8)
我们只给一个索引文件地址到播放器,这样播放器的输入与普通视频播放统一了,即只有一个播放地址。 合并上述两个索引文件,生成 一个新的复合索引文件。
合并后的索引文件:
#EXTM3U
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="en",LANGUAGE="en",URI="https://xxxx.com/xxxx/output_sub_EN.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="cn",LANGUAGE="cn",URI="https://xxxx.com/xxxx/output_sub_CN.m3u8"
#EXT-X-STREAM-INF:SUBTITLES="subs",BANDWIDTH=2000,CODECS="mp4a.40.2, avc1.64001f",RESOLUTION=1920x1080
75118df9-95f2-46a1-946d-d1ba57b3b5ac_avraw.m3u8
最终的复合索引文件,我们就可以给到播放器,由播放器来解析并渲染直播视频和字幕。 注意:这里的复合索引文件遵照HLS标准协议(苹果公司推出的),因此可以直接在Safari浏览器中播放字幕。
字幕和音视频时间对齐
字幕与音视频是独立的流,需要做时间对齐。
两者的时间戳(PTS),统一由推流端编码器产生,确保时间戳是一致的,单位是毫秒。
注意:时间戳初始值是0,由于是推流端编码器产生,如果推流端断流后重新推流,则时间戳会归0,重新计数。
在播放器端,需要根据字幕和音视频中的时间戳,做时间对齐,然后渲染播放。
在Chrome和Safari浏览器,由于采用标准的时间戳方案,它们能够默认进行对齐播放。
在Native App或桌面客户端播放器中,需要开发者自己开发时间对齐逻辑。
字幕播放
理论上合并字幕在播放器播放的时候不需要额外的处理,播放器会自动解析播放。但有可能因为字幕产生时间太慢,错过了对应视频的播放时间,浏览器会放弃了渲染字幕。
解决问题的办法就是增加直播延迟,让视频播放等待字幕生成。 延迟分2类:
- 推流端延时:无法达成我们想要的结果,因为它会更改时间戳,时间戳都被延迟了。
- 拉流端延迟:我们选择了增大HLS切片大小,同样可以起到延迟效果。缺点就是直播开始会有很大的延迟。
总结
Q1:没有字幕文件的视频,要语音识别转字幕,生成字幕后加载到视频中。
Q2:有Srt、Webvtt 字幕文件,直接加载到视频中。
Q3:有txt文本,要先转换成srt/webvtt字幕后再加载到视频中。
Q4:直播中的实时字幕需要创建字幕流对齐直播流时间轴。
无论硬字幕还是软字幕都存在字幕与音视频时间对齐的问题。
软字幕需要不同播放器进行适配。