0.引言
阅读本文前,可以先阅读前面文章,能够帮助你更好理解本篇文章。文章列表如下:
SRS流媒体服务器之RTMP协议分析(2)
SRS流媒体框架分析(1)
SRS流媒体之RTMP推流框架分析(2)
SRS流媒体之RTMP拉流框架分析(3)
SRS流媒体服务器之RTMP协议分析(1)
简述SRS流媒体服务器相关技术
流媒体推拉流实战之RTMP协议分析(BAT面试官推荐)
流媒体服务器架构与应用分析
手把手搭建流媒体服务器详细步骤
手把手搭建FFmpeg的Windows环境
超详细手把手搭建在ubuntu系统的FFmpeg环境
HTTP实战之Wireshark抓包分析
本篇文章主要讲解以下内容:
(1)使用ffmpeg推流,理清数据处理逻辑。
(2)meta data 、audio data、video data是怎样发给消费者?
(3)讲清gop cache缓存分析。
1.RTMP推流消息处理流程(结合源码分析)
rtmp推流时的数据处理入口,函数间的调用关系如下图:
推流端把rtmp数据推上来后,需要调用SrsPublishRecvThread::consume(xxx)去处理和分发不同类型的数据,接着调用conn->handle_publish_message(xxx),继续调用process_publish_message(xxx),根据msg类型不同,分别调用on_meta_data,on_audio,on_video,对应的也要拷贝不同数据的头信息给消费者。
![430d28d76d3b2cf75cd6825266851072.png](https://i-blog.csdnimg.cn/blog_migrate/03608c9407a351d7752dcd6abada7265.jpeg)
在这里,先回顾下前面的文章内容,SRS流媒体服务器中,正真去读取数据,是在SrsRecvThread::do_cycle,源码入下:
![bdbd85f1f72eabcbc89c6da0ae75bd41.png](https://i-blog.csdnimg.cn/blog_migrate/70b99ca526fb3dc87eef1456fb90b631.jpeg)
SrsRecvThread::do_cycle里调用consume,RTMP推流时的数据入口,如下函数,源码入下:
![1e07c04be02685c37233f9644e0f6f92.png](https://i-blog.csdnimg.cn/blog_migrate/8ed468f0851f3405462d4db000e04393.jpeg)
在consume里调用handle_publish_message(_source,msg),处理控制命令消息以及调用process_publish_message(source, msg)处理音视频消息。处理完后,就存放在source执行的内存里,源码入下:
srs_error_t SrsSource::on_video(SrsCommonMessage* shared_video){ srs_error_t err = srs_success; // monotically increase detect. if (!mix_correct && is_monotonically_increase) { if (last_packet_time > 0 && shared_video->header.timestamp < last_packet_time) { is_monotonically_increase = false; srs_warn("VIDEO: stream not monotonically increase, please open mix_correct."); } } last_packet_time = shared_video->header.timestamp; // drop any unknown header video. // @see https://github.com/ossrs/srs/issues/421 if (!SrsFlvVideo::acceptable(shared_video->payload, shared_video->size)) { char b0 = 0x00; if (shared_video->size > 0) { b0 = shared_video->payload[0]; } srs_warn("drop unknown header video, size=%d, bytes[0]=%#x", shared_video->size, b0); return err; } // convert shared_video to msg, user should not use shared_video again. // the payload is transfer to msg, and set to NULL in shared_video. SrsSharedPtrMessage msg; if ((err = msg.create(shared_video)) != srs_success) { return srs_error_wrap(err, "create message"); } // directly process the audio message. if (!mix_correct) { return on_video_imp(&msg); } // insert msg to the queue. mix_queue->push(msg.copy()); // fetch someone from mix queue. SrsSharedPtrMessage* m = mix_queue->pop(); if (!m) { return err; } // consume the monotonically increase message. if (m->is_audio()) { err = on_audio_imp(m); } else { err = on_video_imp(m); } srs_freep(m); return err;}
在函数process_publish_message(source, msg)中处理音视频、onMetaData等数据消息,source->on_audio(msg),source->on_video(msg),rtmp->decode_message(msg, &pkt),source->on_edge_proxy_publish。由于onMetaData数据包会先过来,一般会先处理onMetaData。源码如下:
srs_error_t SrsSource::on_video_imp(SrsSharedPtrMessage* msg){ srs_error_t err = srs_success; bool is_sequence_header = SrsFlvVideo::sh(msg->payload, msg->size); // whether consumer should drop for the duplicated sequence header. bool drop_for_reduce = false; if (is_sequence_header && meta->previous_vsh() && _srs_confi