描述
hls+与传统hls不同,传统hls在服务端没有状态,服务端包含大量碎数据,客户端在不断执行下载,而hls+则会记录每一个客户端的状态。
根据每次进入的http,通过session ID进行绑定。由于第1次发送hls请求时客户端是不知道sessionID的,如果服务器获取到一个没有session ID的连接,则认为此客户端为第1次进入。客户端会接收到一个主m3u8的回复,主m3u8回复中会告诉客户端一个新的地址,其中包含一个session ID。客户端得到携带有session ID的url连接之后就使用这个新url,服务器也就可获取相应session ID并对客户端进行身份区分。
为什么要记录这个状态?这主要是因为服务器不是将数据直接写入硬盘而是放进内存,它需要知道每一个用户、每一个客户端的下载进度,并根据不同的进度从内存中定位ts数据。
hls+和http-ts它们共用了一个 ts buffer,并且hls+是实时的从buffer中定位ts内容。所以对于hls+来说,并没有真正的ts数据产生,只是记录每一个文件在内存里面的偏移量。因此hls+不存在读写的问题,在做hls服务时,以前可能会遇到过一个问题——读写硬盘的瓶颈。机械硬盘的读写速度比较慢,普遍的解决思路就是挂载一个虚拟硬盘,将内存映射到目录中进行读写。如果采用的是hls+的方案,就可以省去挂载的操作,对于内存也并没有太多的消耗。而且如果同时有hls+以及 http-ts的需求,此时对于内存的利用率是非常高的。
优点
- hls客户端也能像rtmp连接一样触发notify,可以复用pull、鉴权、在线数统计等等操作。
- hls+ 使用内存切片,有效解决硬盘IO瓶颈。
- hls+ 为每个客户端维持一个独立的进度,能够有效解决传统hls起播时可能长时间没有关键帧的情况,提高首屏显示速度。
配置
hls2
Syntax: hls2 on|off
Context: rtmp, server, application
- Desc
hls+开关。
无默认值,需要显示配置
- For example
hls2 on;
除了需要在rtmp{}中使用上述配置外,还需要在http{}中添加配置供客户端播放使用。
rtmp { server { listen 1935; application live { live on; hls2 on; mpegts_cache_time 20s; hls2_fragment 2000ms; hls2_max_fragment 3s; hls2_playlist_length 6s; } } } http { server { listen 80; location / { chunked_transfer_encoding on; root html/; } location /hls2 { hls2_live 1935 app=live; } } }
hls2_fragment
Syntax: hls2_fragment time
Context: rtmp, server, application
-
Desc
设置HLS切片(ts文件切片)长度。
默认值:5s
-
For example
hls2_fragment 2s;
hls2_max_fragment
Syntax: hls2_max_fragment time
Context: rtmp, server, application
- Desc
单个ts文件切片的最大时长。hls切片的规则是尽量以hls2_fragment为准,并且让每个ts文件尽量以关键帧开头,所以如果码流中迟迟没有关键帧,这个ts切片就会过大,hls2_max_fragment就是为了防止切片过大存在的,当切片时长超过这个值就强制截断。
默认值:hls2_fragment*10
hls2_playlist_length
Syntax: hls2_playlist_length time
Context: rtmp, server, application
-
Desc
设置HLS playlist 长度,也就是m3u8文件记录的播放时长。
默认值:3*hls2_fragment
-
For example
hls2_playlist_length 15s;
hls2_minfrags
Syntax: hls2_minfrags value
Context: rtmp, server, application
- Desc
m3u8文件中最少有几条ts切片记录时返回内容,这对第一次请求m3u8文件的情况意义重大,一般不需要额外配置,保持默认配置即可。
默认值:2
- For example
hls2_mixfrags 2;
hls2_sync
Syntax: hls2_sync time`
Context: rtmp, server, application
- Desc
在打包音频时,服务器会通过采样率计算音频时间戳,然后使用计算出来的时间戳进行打包。如果计算出来的时间戳和推送端推送过来的时间戳相差超过该值则使用推送来的时间戳打包。
默认值:2ms
- For example
hls2_sync 100ms;
hls2_base_url
Syntax: hls2_base_url url
Context: rtmp, server, application
- Desc
如果你希望让播放器下载ts文件的时候使用与m3u8不同的域名可以通过这个来修改,例如不配置此项m3u8中ts记录为 xxx.ts,加了此项配置hls2_base_url http://pingos.me/path; m3u8文件中ts记录则会变为 http://pingos.me/path/xxx.ts。
默认为空
- For example
hls2_base_url http://myserver.com/hls/;
hls2_max_audio_delay
Syntax: hls2_max_audio_delay time
Context: rtmp, server, application
- Desc
服务器在打包ts的音频数据的时候不会将独立的一帧音频内容打包成ts,而是会将n多分音频帧合在一起作为一个PES打包进ts文件中,这个值就是用来控制缓存多久的内容后封装为PES,然后打包进ts文件。
默认值:300ms
- For example
hls2_max_audio_delay 300ms;
hls2_audio_buffer_size
Syntax: hls2_audio_buffer_size value
Context: rtmp, server, application
- Desc
同理hls2_max_audio_delay,这个参数用来设置缓存音频的buffer大小。
默认值:1m
- For example
hls2_audio_buffer_size 1m;
hls2_timeout
Syntax: hls2_timeout time
Context: rtmp, server, application
- Desc
hls+连接超时时间,如果超过这个时间没有数据下发,则断开连接。
默认值:3 * hls2_playlist_length
- For example
hls2_timeout 45s;
HLS+ 多进程配置模板
默认配置模板已经实现了多进程配置,包括HLS+的多进程模式,所以您也可以参考默认配置模板。
- rtmp推流地址:rtmp://ip/live/流名
- hls+ 播放地址:http(s)://ip/hls2/流名.m3u8
user root;
daemon on;
master_process on;
worker_processes 4;
error_log logs/error.log info;
worker_rlimit_nofile 102400;
worker_rlimit_core 2G;
working_directory /tmp;
pid logs/nginx.pid;
events {
use epoll;
worker_connections 1024;
multi_listen unix:/tmp/http 80;
multi_listen unix:/tmp/rtmp 1935;
dynamic_refresh_interval 5s;
dynamic_domain_buckets 1001;
resolver 114.114.114.114 valid=1m;
resolver_timeout 30s;
}
#stream_zone buckets=1024 streams=4096;
#dynamic_conf conf/nginx_dynamic.conf 10;
#dynamic_log logs/dynamic.log info;
rtmp {
server {
listen 1935;
rtmp_auto_pull on;
rtmp_auto_pull_port unix:/tmp/rtmp;
application live {
live on;
hls2 on;
mpegts_cache_time 20s;
hls2_fragment 2000ms;
hls2_max_fragment 3000ms;
hls2_playlist_length 6000ms;
}
}
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_X-Forwarded-For" "$http_X-Real-IP" "$host"';
access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#reset_server_name www.test1.com www.test2.com;
#gzip on;
upstream hlsm {
# hash $remote_addr consistent;
hash $arg_session consistent;
# 这里需要注意,你要开几个进程,就要按这个规则写几条记录
server unix:/tmp/http.0;
server unix:/tmp/http.1;
server unix:/tmp/http.2;
server unix:/tmp/http.3;
}
server {
listen 80;
listen 443 ssl;
ssl_certificate /usr/local/pingos/cert/full_chain.pem;
ssl_certificate_key /usr/local/pingos/cert/privkey.pem;
location /hlsm {
hls2_live 1935 app=live;
add_header 'Access-Control-Allow-Origin' '*';
add_header Cache-Control no-cache;
add_header "Access-Control-Allow-Credentials" "true";
add_header "Access-Control-Allow-Methods" "*";
add_header "Access-Control-Allow-Headers" "Content-Type,Access-Token";
add_header "Access-Control-Expose-Headers" "*";
}
location /hls2 {
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 1M;
proxy_busy_buffers_size 2M;
proxy_max_temp_file_size 0;
set $hls_args location=/hls2&scheme=$scheme;
if ($args) {
set $hls_args $args&location=/hls2&scheme=$scheme;
}
proxy_set_header Host $host:$server_port;
rewrite ^/(.*)/(.*)\.(.*)$ /hlsm/$2.$3?$hls_args break;
proxy_pass http://hlsm;
}
location / {
chunked_transfer_encoding on;
root html/;
}
}
}