Featured image of post dash实时转换hls流媒体播放

dash实时转换hls流媒体播放

本文主要是探讨下b站的音视频流分离dash格式实时转为hls流媒体,以方便在旧的播放器上播放。

什么是DASH

dash是基于HTTP的动态自适应流(英語:Dynamic Adaptive Streaming over HTTP,也称MPEG-DASH)的简称。现在b站最新的视频都是返回这种格式,并且是音视频分离的。b站dash实践可以参考这篇ppt: MPEG-DASH在bilibili的应用与实践

转换HLS的实现方式

b站dash音视频分别为单独的两个链接,不同的码率和编码对应不同的链接,下面只是使用其中一个音视频链接来举例。实现方式如下:

  1. 提供生成m3u8文件的http服务,m3u8视频块根据时长(duration)切分为5秒为一片,m3u8格式如下:
     #EXTM3U
     #EXT-X-VERSION:3
     #EXT-X-MEDIA-SEQUENCE:0
     #EXT-X-ALLOW-CACHE:YES
     #EXT-X-TARGETDURATION:5
     #EXT-X-PLAYLIST-TYPE:VOD
     #EXTINF: 5.000000,
     http://xxx/api/hls/segments/1
     #EXTINF: 5.000000,
     http://xxx/api/hls/segments/2
     ....
    
    拿不到总的时长的话,可以通过ffprobe命令获取:
    ffprobe -v quiet -print_format json -show_format "http://xxx/video.m4s"
    
    http服务的响应头content-type需设为application/vnd.apple.mpegurl
  2. 提供切片下载的http服务,如上面m3u8文件中的http://xxx/api/hls/segments/1,切片可以通过ffmpeg进行音视合并和切分,命令如下:
    # 切分从视频第(-ss)5.00秒开始,时长(-t)5.00秒
    # -ss和-initial_offset数值需要根据当前切片递增
    ffmpeg -timelimit 45  -ss 5.00 -i http://xxx/video.m4s -ss 5.00 -i http://xxx/audio.m4s -t 5.00  -c:v libx264 -preset veryfast -c:a copy -force_key_frames "expr:gte(t,n_forced*5.000)" -f ssegment -segment_time 5.00 -initial_offset 5.00 pipe:out%03d.ts
    
    # 同时合并字幕xxx.srt
    ffmpeg -timelimit 45  -ss 5.00 -copyts -i http://xxx/video.m4s -ss 5.00 -i http://xxx/audio.m4s -t 5.00  -vf subtitles=xxx.srt -c:v libx264 -preset veryfast -c:a copy -force_key_frames "expr:gte(t,n_forced*5.000)" -f ssegment -segment_time 5.00 -initial_offset 5.00 -ss 5.00 pipe:out%03d.ts
    
    本命令是把重新编码后的视频数据输出到控制台,需要http服务把输出数据实时写入到响应中,这样播放器就能实时下载播放了

会遇到的问题

ffmpeg切片时音频使用了copy命令,但视频却使用libx264重新编码,导致转码很慢,而且cpu占用居高不下,为什么视频不也用copy模式,避免重新转码?

这是因为ffmpeg视频copy模式切片时只能根据关键帧切分,这样会导致每个切片可能会多几帧,播放时出现画面重复播放和声画不同步,具体问题可参考:https://www.jianshu.com/p/f7d83fdec111

切片重新编码是避免不了了,如何可以提高转码速度,降低cpu占用?

——视频编码硬件加速!

ffmpeg硬件加速

视频编码硬件加速主要有如下几种:

  • VAAPI:intel集显支持,是openwrt中最常见和使用的
  • QSV:intel集显支持,可在intel产品规格页搜索自己的cpu,看下有没支持Quick Sync Video
  • NVENC:nvidia显卡支持,openwrt中一般没独立显卡,很少使用到

这里只介绍最常用的vaapi方式,ffmpeg编码时使用vaapi硬件加速切片命令如下:

# 开启vaapi硬件加速编码
ffmpeg -vaapi_device /dev/dri/renderD128 -timelimit 45  -ss 5.00 -i http://xxx/video.m4s -ss 5.00 -i http://xxx/audio.m4s -t 5.00  -vf 'format=nv12,hwupload' -c:v h264_vaapi -c:a copy -force_key_frames "expr:gte(t,n_forced*5.000)" -f ssegment -segment_time 5.00 -initial_offset 5.00 pipe:out%03d.ts

# 同时合并字幕xxx.srt
ffmpeg -vaapi_device /dev/dri/renderD128 -timelimit 45  -ss 5.00  -copyts -i http://xxx/video.m4s -ss 5.00 -i http://xxx/audio.m4s -t 5.00  -vf 'subtitles=xxx.srt,format=nv12,hwupload' -c:v h264_vaapi -c:a copy -force_key_frames "expr:gte(t,n_forced*5.000)" -f ssegment -segment_time 5.00 -initial_offset 5.00  -ss 5.00 pipe:out%03d.ts

-vaapi_device /dev/dri/renderD128-vf 'format=nv12,hwupload'-c:v h264_vaapi这三个参数是必须的

如何在docker中使用硬件加速

假如hls流服务是部署在docker中使用的,打开硬件加速可以使用已经安装了vaapi支持的镜像。jrottenberg/ffmpeg有生成好的支持vaapi的docker镜像,镜像名称带有vaapi标签,可自行搜索需要的ffmpeg版本使用

docker启动时,需要使用--device参数绑定显卡设备:

docker run --device /dev/dri:/dev/dri  jrottenberg/ffmpeg:vaapi

在openwrt中使用的话中,可在docker配置页device栏绑定显卡设备

图片

参考资料

Built with Hugo
主题 StackJimmy 设计