0.引言
阅读本文前,可以先阅读前面文章,能够帮助你更好理解本篇文章。文章列表如下:
SRS流媒体框架分析(1)
SRS流媒体之RTMP推流框架分析(2)
SRS流媒体之RTMP拉流框架分析(3)
SRS流媒体服务器之RTMP协议分析(1)
简述SRS流媒体服务器相关技术
流媒体推拉流实战之RTMP协议分析(BAT面试官推荐)
流媒体服务器架构与应用分析
手把手搭建流媒体服务器详细步骤
手把手搭建FFmpeg的Windows环境
超详细手把手搭建在ubuntu系统的FFmpeg环境
HTTP实战之Wireshark抓包分析
上篇文章主要是通过推流分析来讲解RTMP协议传输的过程,本篇文章通过拉流来讲解RTMP协议传输的过程。由于要使用WireShark抓包来分析,这时候推流就不能在win上使用ffmpeg(如果这样使用,在拉流时,会影响WireShark抓包),而是在ubuntu上使用ffmpeg推流。
讲解本篇文章前,补充下上篇文章的内容,关于推流客户端和SRS流媒体服务器的函数对应关系。
ffmpeg推流客户端 SRS流媒体服务器
gen_connect()--------发送--------------------------->SrsRtmpServer::connect_app(SrsRequest* req)
handle_invoke_result
gen_release_stream 和gen_fcpublish_stream----------发送------->SrsFMLStartPacket
handle_invoke_result
gen_create_stream-------------------发送------------------->SrsCreateStreamPacket
handle_invoke_result
1.拉流抓包分析
无论是拉流还是推流,交互协议都是固定流程,要是深入研究,需要按照spec去分析。
在ubuntu上使用ffmpeg推流命令:
ffmpeg -re -i source.200kbps.768x320.flv -vcodec copy -acodec copy -f flv -y rtmp://xxx.xxx.xxx.xxx/live/livestream
推流界面如下:
在win上使用ffmpeg去拉流,输入命令:
ffplay rtmp://xxx.xxx.xxx.xxx/live/livestream -loglevel 56
拉流界面如下:
WireShark抓包分析,
客户端拉流时与推流,大部分情况类似(如应答,设置窗口等),有些不一样。
拉流客户端给SRS流媒体服务器发送:window Acknowledgement Size 2500000|createStream()|_checkbw。拉流端ffmpeg源码如下:
其中gen_release_stream(s, rt)和gen_fcpublish_stream(s, rt)主要是在推流时用作输出使用,发送给SRS流媒体服务器,而gen_window_ack_size(s, rt)主要是在拉流时用作输入使用,拉流客户端发送给SRS流媒体服务器。
static int handle_invoke_result(URLContext *s, RTMPPacket *pkt){ RTMPContext *rt &#61; s->priv_data; char *tracked_method &#61; NULL; int ret &#61; 0; if ((ret &#61; find_tracked_method(s, pkt, 10, &tracked_method)) <0) return ret; if (!tracked_method) { /* Ignore this reply when the current method is not tracked. */ return ret; } if (!strcmp(tracked_method, "connect")) { if (!rt->is_input) { if ((ret &#61; gen_release_stream(s, rt)) <0) goto fail; if ((ret &#61; gen_fcpublish_stream(s, rt)) <0) goto fail; } else { if ((ret &#61; gen_window_ack_size(s, rt)) <0) goto fail; } if ((ret &#61; gen_create_stream(s, rt)) <0) goto fail; if (rt->is_input) { /* Send the FCSubscribe command when the name of live * stream is defined by the user or if it&#39;s a live stream. */ if (rt->subscribe) { if ((ret &#61; gen_fcsubscribe_stream(s, rt, rt->subscribe)) <0) goto fail; } else if (rt->live &#61;&#61; -1) { if ((ret &#61; gen_fcsubscribe_stream(s, rt, rt->playpath)) <0) goto fail; } } } else if (!strcmp(tracked_method, "createStream")) { double stream_id; if (read_number_result(pkt, &stream_id)) { av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()"); } else { rt->stream_id &#61; stream_id; } if (!rt->is_input) { if ((ret &#61; gen_publish(s, rt)) <0) goto fail; } else { if (rt->live !&#61; -1) { if ((ret &#61; gen_get_stream_length(s, rt)) <0) goto fail; } if ((ret &#61; gen_play(s, rt)) <0) goto fail; if ((ret &#61; gen_buffer_time(s, rt)) <0) goto fail; } } else if (!strcmp(tracked_method, "getStreamLength")) { if (read_number_result(pkt, &rt->duration)) { av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()"); } }fail: av_free(tracked_method); return ret;}
注意:根据实际情况的抓包分析&#xff0c;WireShark有时候会漏掉一些包。只能当做参考使用。
确定服务器发送过来的字节&#xff0c;拉流客户端需要回应服务器ACK。源码如下:
static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt){ RTMPContext *rt &#61; s->priv_data; if (pkt->size <4) { av_log(s, AV_LOG_ERROR, "Too short window acknowledgement size packet (%d)", pkt->size); return AVERROR_INVALIDDATA; } rt->receive_report_size &#61; AV_RB32(pkt->data); if (rt->receive_report_size <&#61; 0) { av_log(s, AV_LOG_ERROR, "Incorrect window acknowledgement size %d", rt->receive_report_size); return AVERROR_INVALIDDATA; } av_log(s, AV_LOG_DEBUG, "Window acknowledgement size &#61; %d", rt->receive_report_size); // Send an Acknowledgement packet after receiving half the maximum // size, to make sure the peer can keep on sending without waiting // for acknowledgements. rt->receive_report_size >>&#61; 1; return 0;}
2.重点要分析的内容
(1)metadata只发一次&#xff0c;流媒体会缓存metadata。
(2)SRS流媒体服务器会cache缓存I帧。
(3)协议转换&#xff0c;如rtmp->hls&#xff0c;rtmp->http-flv&#xff0c;这个是需要深入研究。
(4)超时退出
(5)码率统计
3.总结
本篇文章主要是对上篇文章补充及对拉流抓包分析。需要结合前面文章仔细查看。迎关注&#xff0c;转发&#xff0c;点赞&#xff0c;收藏&#xff0c;分享&#xff0c;评论区讨论。
后期关于项目的知识&#xff0c;会在微信公众号上更新&#xff0c;如果想要学习项目&#xff0c;可以关注微信公众号“记录世界 from antonio”