SRS支持Haivision编码器,及解决HLS纯音频爆音

2022-03-18 17:10:43 浏览数 (1)

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

0 人点赞