Haivision是另外一只野鸡编码器,黑爷要支持十万火急,所以看了下,Haivision的协议序列不是FMLE也不是FFMPEG也不是Flash,是自己的一个私有协议:
如果看不太明白,那么下面是个总结。
FFMPEG的消息序列,也就是推流的协议了:
代码语言:javascript复制C/S: Handshake
C: ConnectApp() tcUrl=xxx
S: Ack Size 2500,000
S: Set Peer Bandwidth 2500,000
S: Set Chunk Size 60,000
C: Set Chunk Size 60,000
S: ConnectApp() _result
S: onBWDone()C: releaseStream FCPublish(s0)
C: createStream()
S: releaseStream _result
C: _checkbw()
S: FCPublish() _result
S: createStream() _result
C: publish(s0)
S: onFCPublish()
S: onStatus()
Haivision的消息序列:
代码语言:javascript复制C/S: Handshake
C: Set Chunk Size 4096 ConnectApp() tcUrl=xxx
S: Ack Size 2500,000
S: ConnectApp() _result Set Peer Bandwidth Set Chunk Size 60,000C: _checkbw()
S: _checkbw() _result
C: createStream()
S: createStream() _result
C: FCPublish()
S: FCPublish() _result
C: publish()
S: onFCPublish()
S: onStatus()
----OK------
C: Stream Begin
C: @setDataFrame()
C: AudioData
C: VideoData
可见是完全不同的,花了2个小时才支持,看来不仅仅是国内喜欢自己搞,国外也是一样坑爹啊。。。
其他信息可以参考:https://github.com/ossrs/srs/issues/844
第二个重要的问题,是解决了HLS纯音频爆音的问题,爆音的问题查明白了,是因为采样率导致的时间戳不能整除,所以会有误差,Safari比较精确,所以会有噗噗的声音。
验证如下,先看8000HZ采样率,一个AAC帧是1024个采样,所以一个AAC帧是:
代码语言:javascript复制1024/8000.0=0.128s=128ms
如果是16000HZ采样率,则每个AAC帧是:1024/16000.0=0.064s=64ms
SRS配置如下:
代码语言:javascript复制listen 1935;
max_connections 1000;
daemon off;
srs_log_tank console;
http_api {
enabled on;
listen 1985;
}
http_server {
enabled on;
listen 8080;
}
vhost __defaultVhost__ {
hls {
enabled on;
hls_fragment 2;
hls_window 60;
hls_vcodec vn;
hls_path ./objs/nginx/html;
hls_m3u8_file [app]/[stream].m3u8;
hls_ts_file [app]/[stream]-[seq].ts;
}
}
使用FFMPEG转码,输出16KHZ的音频:
代码语言:javascript复制ffmpeg -re -i doc/source.200kbps.768x320.flv
-vn -acodec libfdk_aac -ar 16000 -ac 2 -b:a 48k
-f flv -y rtmp://127.0.0.1/live/livestream
用Safari访问:http://localhost:8080/live/livestream.html ,可以发现,没有爆音。
转码时,输出44100HZ的音频:
代码语言:javascript复制ffmpeg -re -i doc/source.200kbps.768x320.flv
-vn -acodec libfdk_aac -ar 44100 -ac 2 -b:a 48k
-f flv -y rtmp://127.0.0.1/live/livestream
可以听到每隔4秒左右会有噗噗,或者滋滋的杂音,每隔一片就会有。得仔细听才会有。
原因是什么?在44100HZ时,每个AAC帧是:
代码语言:javascript复制1024/44100.0=0.02321995s=23.21995ms
如果取整,则每个帧会有0.2ms的误差,Safari比较敏感,所以容易出现问题。
如何解决这个问题?NGINX将多个AAC帧合并成一个TS Packet,然后累计计算时间。 如果直接每帧计算时间:
代码语言:javascript复制90000*1024/44100.0=2089.795918367347
这样误差可以降低到1/90。
例如,一个audio的信息是:
代码语言:javascript复制(lldb) p audio->timestamp
(int64_t) $8 = 23
(lldb) p audio->timestamp*90
(long long) $9 = 2070
但是通过samples个数重新计算的结果是:
代码语言:javascript复制int64_t dts = 90000 * aac_samples / srs_flv_srates[format->acodec->sound_rate];
(lldb) p dts
(int64_t) $6 = 2089
200ms之后:
代码语言:javascript复制(lldb) p audio->timestamp
(int64_t) $14 = 209
(lldb) p audio->timestamp*90
(long long) $15 = 18810
(lldb) p dts
(int64_t) $16 = 18808
结果,没有噗噗的爆音了。
详细信息参考:https://github.com/ossrs/srs/issues/547#issuecomment-294350544