一、前言
SRS流媒体服务器支持rtmp协议,但是rtmp协议仅仅支持PC直播。移动端直播需要HLS协议,HLS协议是由苹果公司发布,用于移动端视频直播,后来Android也对HLS做了友好支持。所以,SRS流媒体服务器支持rtmp协议和hls协议,满足了PC和移动端直播要求。
HLS协议有两个关键文件:.m3u8文件和.ts文件:
- .m3u8文件:播放控制文件,存放了地址和播放参数。
- .ts文件:真正存储视频文件。
相关HLS协议详细说明参见:HLS协议详解。
SRS流媒体接受到通过rtmp传输协议传输的编码格式为H264/AAC(注意:HLS协议只支持Video编码:H264;Audio编码:AAC/mp3)音视频数据,进行切片成.m3u8文件和.ts文件,存储在磁盘或者内存当中(注意:一般为了提高cpu使用率,将.m3u8和.ts文件存储在内存中)。再通过nginx分发到端(注意:nginx工作目录要和存储.m3u8路径一致)。
HLS切片处理,其实就是ts编码的处理,通过将H264/AAC编码数据按照TS协议来分成一个一个的TS包。TS协议规定,TS首包内容为PAT(Program Association Table 节目关联表)表,其PID为0x0;接下来为PMT(Program Map Table 节目映射表)表,其PID为0x1001。其次,视频帧PID为:0x100,音频PID为:0x101。后面TS包为实际音视频数据。
二、代码分析
SRS源码相关其他总结:
SRS(simple-rtmp-server)流媒体服务器源码分析--系统启动
SRS(simple-rtmp-server)流媒体服务器源码分析--RTMP消息play
SRS(simple-rtmp-server)流媒体服务器源码分析--RTMP信息Publish
SRS(simple-rtmp-server)流媒体服务器源码分析--HLS切片
SRS源码HLS处理框架如下:
接着SRS(simple-rtmp-server)流媒体服务器源码分析--RTMP消息play分析,在接受到rtmp信息之后,进行HLS处理。
int SrsSource::on_video_imp(SrsSharedPtrMessage* msg)
在函数中,除了转发给client和forward之外,还有HLS处理。注意:在HLS这一讲中,只分析跟video相关的代码,audio类同。
#ifdef SRS_AUTO_HLS
if ((ret = hls->on_video(msg, is_sequence_header)) != ERROR_SUCCESS) {
// apply the error strategy for hls.
// @see https://github.com/ossrs/srs/issues/264
std::string hls_error_strategy = _srs_config->get_hls_on_error(_req->vhost);
if (srs_config_hls_is_on_error_ignore(hls_error_strategy)) {
srs_warn("hls process video message failed, ignore and disable hls. ret=%d", ret);
// unpublish, ignore ret.
hls->on_unpublish();
// ignore.
ret = ERROR_SUCCESS;
} else if (srs_config_hls_is_on_error_continue(hls_error_strategy)) {
if (srs_hls_can_continue(ret, cache_sh_video, msg)) {
ret = ERROR_SUCCESS;
} else {
srs_warn("hls continue video failed. ret=%d", ret);
return ret;
}
} else {
srs_warn("hls disconnect publisher for video error. ret=%d", ret);
return ret;
}
}
#endif
进入on_video(),
int SrsHls::on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps)
{
int ret = ERROR_SUCCESS;
if (!hls_enabled) {
return ret;
}
// update the hls time, for hls_dispose.
last_update_time = srs_get_system_time_ms();
SrsSharedPt