• 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

  • 相关阅读:
    Java的几种常用设计模式
    面向切面编程AOP
    面向过程编程、面向对象编程
    Java基础之集合与泛型
    Spring mvc中自定义拦截器
    Hibernate框架hibernate.cfg.xml配置文件,配置自动生成表结构策略。
    Notepad++打开xml文件显示crlf的问题
    java框架
    潜龙博客地址
    联通
  • 原文地址:https://www.cnblogs.com/jimodetiantang/p/9135343.html
Copyright © 2020-2023  润新知