zoukankan      html  css  js  c++  java
  • SRS之分发HLS

    来自: Delivery HLS

    1. 综述

    SRS支持HLS/RTMP两种成熟而且广泛应用的流媒体分发方式。

    RTMP指Adobe的RTMP(Realtime Message Protocol),广泛应用于低延时直播,也是编码器和服务器对接的实际标准协议,在PC(Flash)上有最佳观看体验和最佳稳定性。

    HLS指Apple的HLS(Http Live Streaming),本身就是Live(直播)的,不过Vod(点播)也能支持。HLS是Apple平台的标准流媒体协议,和RTMP在PC上一样支持得天衣无缝。

    HLS和RTMP两种分发方式,就可以支持所有的终端。RTMP参考 RTMP分发

    RTMP和HLS的比较参考: RTMP PK HLS

    部署分发HLS的实例,参考: Usage: HLS

    2. 应用场景

    • 跨平台:PC主要的直播方案是RTMP,也有一些库能播放HLS,譬如jwplayer,基于osmf的hls插件也一大堆。所以实际上如果选一种协议能跨PC/Android/IOS,那就是HLS。
    • IOS上苛刻的稳定性要求:IOS上最稳定的当然是HLS,稳定性不差于RTMP在PC-flash上的表现。
    • 友好的CDN分发方式:目前CDN对于RTMP也是基本协议,但是HLS分发的基础是HTTP,所以CDN的接入和分发会比RTMP更加完善。能在各种CDN之间切换,RTMP也能,只是可能需要对接测试。
    • 简单:HLS作为流媒体协议非常简单,apple支持得也很完善。Android对HLS的支持也会越来越完善。至于DASH/HDS,好像没有什么特别的理由,就像linux已经大行其道而且开放,其他的系统很难再广泛应用。

    3. HLS 介绍

    HLS是提供一个m3u8地址,Apple的Safari浏览器直接就能打开m3u8地址,譬如:

    http://demo.srs.com/live/livestream.m3u8
    

    Android不能直接打开,需要使用html5的video标签,然后在浏览器中打开这个页面即可,譬如:

    <!-- livestream.html -->
    <video width="640" height="360"
            autoplay controls autobuffer 
            src="http://demo.srs.com/live/livestream.m3u8"
            type="application/vnd.apple.mpegurl">
    </video>
    

    HLS的m3u8,是一个ts的列表,也就是告诉浏览器可以播放这些ts文件,譬如:

    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-MEDIA-SEQUENCE:64
    #EXT-X-TARGETDURATION:12
    #EXTINF:11.550
    livestream-64.ts
    #EXTINF:5.250
    livestream-65.ts
    #EXTINF:7.700
    livestream-66.ts
    #EXTINF:6.850
    livestream-67.ts
    

    有几个关键的参数,这些参数在SRS的配置文件中都有配置项:

    • EXT-X-TARGETDURATION:所有切片的最大时长。有些Apple设备这个参数不正确会无法播放。SRS会自动计算出ts文件的最大时长,然后更新m3u8时会自动更新这个值。用户不必自己配置。
    • EXTINF:ts切片的实际时长,SRS提供配置项hls_fragment,但实际上的ts时长还受gop影响,详见下面配置HLS的说明。
    • ts文件的数目:SRS可配置hls_window,指定m3u8中保存多少个切片,SRS会自动清理旧的切片。
    • livestream-67.ts:SRS会自动维护ts切片的文件名,在编码器重推之后,这个编号会继续增长,保证流的连续性。直到SRS重启,这个编号才重置为0。

    譬如,每个ts切片为10秒,窗口为60秒,那么m3u8中会保存6个ts切片。

    4. HLS 工作流程

    1. FFMPEG 或 FMLE 或编码器,推送 RTMP 流到 SRS,编码为 H264/AAC(其他编码器需要 SRS 转码)
    2. SRS 将 RTMP 切片为 TS,并生成 M3U8。若流非 H264 和 AAC,则停止输出 HLS(可使用 SRS 转码到 SRS 其他 vhost 或流,然后再切 HLS)。
    3. 访问 M3U8,SRS 内置的 HTTP 服务器(或者通用 HTTP 服务器)提供 HTTP 服务。

    注意:SRS 只需要在 Vhost 上配置 HLS,会自动根据流的 app 创建目录,但是配置的 hls_path 必须自己创建。

    5. HLS 配置

    conf/full.conf中的with-hls.vhost.com是HLS配置的实例,可以拷贝到默认的Vhost,例如:

    vhost __defaultVhost__ {
        hls {
            # whether the hls is enabled.
            # if off, donot write hls(ts and m3u8) when publish.
            # default: off
            enabled         on;
            # the hls fragment in seconds, the duration of a piece of ts.
            # default: 10
            hls_fragment    10;
            # the hls m3u8 target duration ratio,
            #   EXT-X-TARGETDURATION = hls_td_ratio * hls_fragment // init
            #   EXT-X-TARGETDURATION = max(ts_duration, EXT-X-TARGETDURATION) // for each
            # @see https://github.com/ossrs/srs/issues/304#issuecomment-74000081
            # default: 1.5
            hls_td_ratio    1.5;
            # the audio overflow ratio.
            # for pure audio, the duration to reap the segment.
            # for example, the hls_fragment is 10s, hls_aof_ratio is 2.0,
            # the segment will reap to 20s for pure audio.
            # default: 2.0
            hls_aof_ratio   2.0;
            # the hls window in seconds, the number of ts in m3u8.
            # defualt: 60
            hls_window      60;
            # the error strategy. canbe:
            #       ignore, disable the hls.
            #       disconnect, require encoder republish.
            #       continue, ignore failed try to continue output hls.
            # @see https://github.com/ossrs/srs/issues/264
            # default: continue
            hls_on_error    continue;
            # the hls output path.
            # the m3u8 file is configed by hls_path/hls_m3u8_file, the defualt is:
            #       ./objs/nginx/html/[app]/[stream].m3u8
            # the ts file is cofiged by hls_path/hls_ts_file, the defualt is:
            #       ./objs/nginx/html/[app]/[stream]-[seq].ts
            # @remark, the hls_path is compatible with srs v1 config.
            # default: ./objs/nginx/html
            hls_path        ./objs/nginx/html;
            # the hls m3u8 file name.
            # we supports some variables to generate the filename.
            #       [vhost], the vhost of stream.
            #       [app], the app of stream.
            #       [stream], the stream name of stream.
            # default: [app]/[stream].m3u8
            hls_m3u8_file   [app]/[stream].m3u8;
            # the hls ts file name.
            # we supports some variables to generate the filename.
            #       [vhost], the vhost of stream.
            #       [app], the app of stream.
            #       [stream], the stream name of stream.
            #       [2006], replace this const to current year.
            #       [01], replace this const to current month.
            #       [02], replace this const to current date.
            #       [15], replace this const to current hour.
            #       [04], repleace this const to current minute.
            #       [05], repleace this const to current second.
            #       [999], repleace this const to current millisecond.
            #       [timestamp],replace this const to current UNIX timestamp in ms.
            #       [seq], the sequence number of ts.
            # @see https://github.com/ossrs/srs/wiki/v2_CN_DVR#custom-path
            # @see https://github.com/ossrs/srs/wiki/v2_CN_DeliveryHLS#hls-config
            # default: [app]/[stream]-[seq].ts
            hls_ts_file     [app]/[stream]-[seq].ts;
            # whether use floor for the hls_ts_file path generation.
            # if on, use floor(timestamp/hls_fragment) as the variable [timestamp],
            #       and use enahanced algorithm to calc deviation for segment.
            # @remark, when floor on, recommend the hls_segment >= 2*gop.
            # defualt: off
            hls_ts_floor    off;
            # the hls entry prefix, which is base url of ts url.
            # if specified, the ts path in m3u8 will be like:
            #       http://your-server/live/livestream-0.ts
            #       http://your-server/live/livestream-1.ts
            #       ...
            # optional, defualt to empty string.
            hls_entry_prefix http://your-server;
            # the default audio codec of hls.
            # when codec changed, write the PAT/PMT table, but maybe ok util next ts.
            # so user can set the default codec for mp3.
            # the available audio codec: 
            #       aac, mp3, an
            # default: aac
            hls_acodec      aac;
            # the default video codec of hls.
            # when codec changed, write the PAT/PMT table, but maybe ok util next ts.
            # so user can set the default codec for pure audio(without video) to vn.
            # the available video codec:
            #       h264, vn
            # default: h264
            hls_vcodec      h264;
            # whether cleanup the old expired ts files.
            # default: on
            hls_cleanup     on;
            # the timeout in seconds to dispose the hls,
            # dispose is to remove all hls files, m3u8 and ts files.
            # when publisher timeout dispose hls.
            # @remark 0 to disable dispose for publisher.
            # @remark apply for publisher timeout only, while "etc/init.d/srs stop" 
            #     always dispose hls.
            # default: 0
            hls_dispose     0;
            # the max size to notify hls,
            # to read max bytes from ts of specified cdn network,
            # @remark only used when on_hls_notify is config.
            # default: 64
            hls_nb_notify   64;
            # whether wait keyframe to reap segment,
            # if off, reap segment when duration exceed the fragment,
            # if on, reap segment when duration exceed and got keyframe.
            # default: on
            hls_wait_keyframe       on;
            
            # on_hls, never config in here, should config in http_hooks.
            # for the hls http callback, @see http_hooks.on_hls of vhost 
            # hooks.callback.srs.com
            # @read https://github.com/ossrs/srs/wiki/v2_CN_DeliveryHLS#http-callback
            # @read https://github.com/ossrs/srs/wiki/v2_CN_DeliveryHLS#http-callback
            
            # on_hls_notify, never config in here, should config in http_hooks.
            # we support the variables to generate the notify url:
            #       [app], replace with the app.
            #       [stream], replace with the stream.
            #       [ts_url], replace with the ts url.
            # for the hls http callback, @see http_hooks.on_hls_notify of 
            # vhost hooks.callback.srs.com
            # @read https://github.com/ossrs/srs/wiki/v2_CN_DeliveryHLS#on-hls-notify
            # @read https://github.com/ossrs/srs/wiki/v2_CN_DeliveryHLS#on-hls-notify
        }
    }
    

    其中 hls 配置就是 HLS 的配置,主要配置项如下:

    • enabled:是否开启 HLS,on/off,默认 off。
    • hls_fragment:秒,指定 ts 切片的最小长度。实际上 ts 文件的长度由以下公式决定:
    ts 文件时长 = max(hls_fragment, gop_size)
    hls_fragment:配置文件中的长度。譬如:5秒。
    gop_size:编码器配置的 gop 的长度,譬如 ffmpeg 指定fps为20帧/秒,gop为200帧,则gop_size=gop/fps=10秒。
    那么,最终ts的时长为max(5, 10) = 10秒。这也是为什么有些流配置了hls_fragment,
    但是ts时长仍然比这个大的原因。
    
    • hls_td_ratio:倍数。控制 m3u8 的 EXT-X-TARGETDURATION,参考 Rewrite HLS写入ts部分
    • hls_aof_ratio:倍数。纯音频时,当 ts 时长超过配置的 hls_fragment 乘以这个系数时就切割文件。例如,但 hls_fragment 是 10 秒,hls_aof_ratio 是 2.0 时,对于纯音频,10s*2.0=20秒时就切割 ts 文件。
    • hls_window:秒,指定 HLS 窗口大小,即 m3u8 中 ts 文件的时长之和,超过总时长后,丢弃第一个 m3u8 中的第一个切片,直到 ts 的总时长在这个配置项范围之内。即 SRS 保证下面的公式:
    hls_window >= sum(m3u8中每个ts的时长)
    
    • hls_path:HLS 的 m3u8 和 ts 文件保存的路径。m3u8 和 ts 文件都保存在这个目录中。
    • hls_m3u8_file:HLS 的 m3u8 文件名,包含可替换的 [vhost], [app] 和 [stream] 变量。
    • hls_ts_file:HLS的ts文件名,包含可替换的一系列变量,参考 dvr variables,另外,[seq] 是 ts 的 sequence number。
    对于RTMP流:rtmp://localhost/live/livestream
    HLS配置路径:
            hls_path        /data/nginx/html;
            hls_m3u8_file   [app]/[stream].m3u8;
            hls_ts_file     [app]/[stream]-[seq].ts;
    那么会生成以下文件:
    /data/nginx/html/live/livestream.m3u8
    /data/nginx/html/live/livestream-0.ts
    /data/nginx/html/live/livestream-1.ts
    /data/nginx/html/live/livestream-2.ts
    最后的HLS地址为:http://localhost/live/livestream.m3u8
    
    • hls_entry_prefix:TS 的 base url。可选默认为空字符串;非空时加在 ts 前面作为 base url。
    对于ts切片:live/livestream-0.ts
    若配置为:hls_entry_prefix http://your-server;
    则最后的TS的URL是:http://your-server/live/livestream-0.ts
    
    • hls_acodec:默认的音频编码。当流的编码改变时,会更新 PMT/PAT 信息;默认是 aac,因此默认的 PMT/PAT 信息是 aac;如果流是 mp3,那么可以配置这个参数为 mp3,避免 PMT/PAT 改变。
    • hls_vcodec:默认的视频编码。当流的编码改变时,会更新 PMT/PAT 信息;默认是 h264. 如果是纯音频 HLS,可以配置为 vn,可以减少 SRS 检测纯音频时间,直接进入纯音频模式。
    • hls_cleanup:是否删除过期的 ts 切片,不在 hls_window 中就是过期。可以关闭清除 ts 切片,实现时移和存储,使用自己的切片管理系统。
    • hls_dispose:HLS 清理的过期时间(秒),系统重启或者超过这个时间时,清理 HLS 的所有文件,包括 m3u8 和 ts。默认为 0,即不清理。
    • hls_wait_keyframe:是否按 gop 切片,即等待到关键帧后开始切片。测试发现 OS X 和 android 上可以不用按 gop 切片。
    • hls_nb_notify:从 notify 服务器读取数据的长度。
    • on_hls:当切片生成时,回调这个 url,使用 POST 回调。用来和自己的系统集成,譬如实现切片移动等。
    • on_hls_notify:当切片生成时,回调这个 url,使用 GET 回调。用来和系统集成,可以使用 [ts_url] 变量,实现预分发(即下载一次 ts 片)。

    部署分发HLS的实例,参考: Usage: HLS

    6. HTTP Callback

    可以配置 on_hls 实现回调,应该在 http_hooks 中配置,而不是在 hls 中配置。

    备注:HLS 热备可以基于这个回调实现,参考 #351

    备注:HLS 热备必须保证两个服务器的切片完全一样,因为负载均衡器或者边缘可能从两个服务器取切片,必须完全一样。因此在切片上保证两个服务器切片完全一致,是一个非常非常复杂的流媒体问题;但是通过业务系统和回调,通过选择两个服务器的切片的方式,可以做到非常简单可靠的 HLS 热备系统。

    7. ON HLS Notify

    可以配置 on_hls_notify 实现 CDN 预分发,应该在 http_hooks 中配置,而不是在 hls 中配置。

    8. HLSAudioOnly

    SRS 支持分发 HLS 纯音频,当 RTMP 流没有视频,且音频为 aac(可以使用转码转为 aac,参考 Usage: Transcode2HLS),SRS 只切片音频。

    若 RTMP 流中已经有视频和音频,需要支持纯音频 HLS 流,可以用转码将视频去掉,参考: 转码: 禁用流。然后分发音频流。

    分发纯音频流不需要特殊配置,和 HLS 分发一样,参考: Usage: HLS

    9. HLS and Forward

    Forward 的流和普通流不做区分,若 forward 的流所在的 VHOST 配置了 HLS,一样会应用 HLS 配置进行切片。

    因此,可以对原始流进行 Transcode 之后,保证流符合 h.264/aac 的规范,然后 forward 到多个配置了 HLS 的 vhost 进行切片。支持多个源站的热备。

    10. HLS and Transcode

    HLS 要求 RTMP 流的编码为 h.264+aac/mp3,否则会自动禁用 HLS,会出现 RTMP 流能看 HLS 流不能看(或者看到的 HLS 是之前的流)。

    Transcode 将 RTMP 流转码后,可以让 SRS 接入任何编码的 RTMP 流,然后转换成 HLS 要求的 h.264/aac/mp3 编码方式。

    配置 Transcode 时,若需要控制 ts 长度,需要配置 配置ffmpeg编码的gop,譬如:

    vhost hls.transcode.vhost.com {
        transcode {
            enabled     on;
            ffmpeg      ./objs/ffmpeg/bin/ffmpeg;
            engine hls {
                enabled         on;
                vfilter {
                }
                vcodec          libx264;
                vbitrate        500;
                vfps            20;
                vwidth          768;
                vheight         320;
                vthreads        2;
                vprofile        baseline;
                vpreset         superfast;
                vparams {
                    g           100;
                }
                acodec          libaacplus;
                abitrate        45;
                asample_rate    44100;
                achannels       2;
                aparams {
                }
                output          rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
            }
        }
    }
    

    该 FFMPEG 转码参数,指定 gop 时长为 100/20 = 5秒,fps 帧率(vfps=20),gop 帧数(g=100)。

    11. HLS M3u8 Examples

    live.m3u8

    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-ALLOW-CACHE:YES
    #EXT-X-TARGETDURATION:13
    #EXT-X-MEDIA-SEQUENCE:430
    #EXTINF:11.800
    news-430.ts
    #EXTINF:10.120
    news-431.ts
    #EXTINF:11.160
    news-432.ts
    

    event.m3u8

    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-ALLOW-CACHE:YES
    #EXT-X-TARGETDURATION:13
    #EXT-X-MEDIA-SEQUENCE:430
    #EXT-X-PLAYLIST-TYPE:EVENT
    #EXTINF:11.800
    news-430.ts
    #EXTINF:10.120
    news-431.ts
    #EXTINF:11.160
    news-432.ts
    

    vod.m3u8

    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-ALLOW-CACHE:YES
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXT-X-TARGETDURATION:12
    #EXTINF:10.120,
    livestream-184.ts
    #EXTINF:10.029,
    livestream-185.ts
    #EXTINF:10.206,
    livestream-186.ts
    #EXTINF:10.160,
    livestream-187.ts
    #EXTINF:11.360,
    livestream-188.ts
    #EXTINF:9.782,
    livestream-189.ts
    #EXT-X-ENDLIST
    

    loop.m3u8

    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-ALLOW-CACHE:YES
    #EXT-X-TARGETDURATION:13
    #EXT-X-MEDIA-SEQUENCE:430
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXTINF:11.800
    news-430.ts
    #EXTINF:10.120
    news-431.ts
    #EXT-X-DISCONTINUITY
    #EXTINF:11.952
    news-430.ts
    #EXTINF:12.640
    news-431.ts
    #EXTINF:11.160
    news-432.ts
    #EXT-X-DISCONTINUITY
    #EXTINF:11.751
    news-430.ts
    #EXTINF:2.040
    news-431.ts
    #EXT-X-ENDLIST
    

    Apple

    https://developer.apple.com/library/ios/technotes/tn2288/_index.html

  • 相关阅读:
    Building Java Projects with Gradle
    Vert.x简介
    Spring及Spring Boot 国内快速开发框架
    dip vs di vs ioc
    Tools (StExBar vs Cmder)which can switch to command line window on context menu in windows OS
    SSO的定义、原理、组件及应用
    ModSecurity is an open source, cross-platform web application firewall (WAF) module.
    TDD中测试替身学习总结
    Spring事务银行转账示例
    台式机(华硕主板)前面板音频接口(耳机和麦克风)均无声的解决办法
  • 原文地址:https://www.cnblogs.com/jimodetiantang/p/9135343.html
Copyright © 2011-2022 走看看