Nginx rtmp 转推push和relay(pull)

系列文章:

Nginx rtmp 推流(publish) 解析_fdsafwagdagadg6576的专栏-CSDN博客
Nginx rtmp 拉流播放(play)_fdsafwagdagadg6576的专栏-CSDN博客
Nginx rtmp Relay(转发pull)_fdsafwagdagadg6576的专栏-CSDN博客
Nginx rtmp 转推_fdsafwagdagadg6576的专栏-CSDN博客
Nginx rtmp 点播流程_fdsafwagdagadg6576的专栏-CSDN博客

config:

启用push功能,将本机(172.16.6.36)/mypush,app中的数据流推送至172.16.6.39服务器下的/myapp app中

application mypush {
    live on;
    push rtmp://172.16.6.39:1935/myapp;
}

配置实现pull功能,172.16.6.39服务器能够从172.16.6.36服务器上拉取数据流,并保存在本机/mypull app中.

application mypush {
    live on;
    push rtmp://172.16.6.39:1935/myapp;
}

启动

ngx rtmp启动过程。rtmp_block,rtmp_recv 时序.
ngx_process_events_and_timers是放入子进程处理。

callback:

ngx_rtmp_cmd_play_init {
        .....
         return ngx_rtmp_play(s, &v);
}

static ngx_int_t
ngx_rtmp_relay_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) {
        ....
        return next_play(s,v);
}
ngx_rtmp_play和next_play关系?
监听play指令的所有模块,组成了一个链表.

  • relay模块注册:

    next_play = ngx_rtmp_play;
    ngx_rtmp_play = ngx_rtmp_relay_play;
头插法:ngx_rtmp_play指向链表头,next_play指向上一个头节点,就是本模块的下一个模块.

  • 调用的是哪个模块的play函数呢?

根据配置,直播调用relay,live模块的play函数。点播调用play模块的play函数.
对于直播来说,relay,live,cmd的调用顺序是如何的呢?
需要按照模块的编译顺序。参见:....
对于直播ngx_rtmp_play先调用ngx_rtmp_relay_play(即使在cmd模块调用,也不是调用ngx_rtmp_cmd_play), 然后ngx_rtmp_relay_play函数调用next_play,是ngx_rtmp_live_play.

整体结构图

在这里插入图片描述

阶段

  • 1 handshake 
  • 2 connect
  • 3 createStream
  • 4 指令publish,play,seek 等
  • 5 发送,接收audio,video

信令和audio,video流独立分开. 码流在ngx_rtmp_live_av执行,与信令函数没有关联.

通信层:
1) handshake
handshake是独立的handshake_send/recv.特别注意此处没有走转推ngx_rtmp_fire_event(s, NGX_RTMP_HANDSHAKE_DONE...).因为此处还没有与被转推的server建立handshake,所以无法connect成功。真正的转推是在接收publish消息
2) ngx_rtmp_receive_message: 
在1)之后使用ngx_rtmp_recv/send接收.
ngx_rtmp_receive_message是message接口,解开rtmp包.然后callback分发。
(这是一个统一enter在ngx_rtmp_handler中,给rtmp,hls等使用,所以先拆开rtmp header,hls是裸流写ts文件,http flv是自己的rw callback).
3) ngx_rtmp_cycle: 进入rtmp业务循环

ngx_rtmp_receive_message详解:

ngx_int_t
ngx_rtmp_receive_message(ngx_rtmp_session_t *s,
        ngx_rtmp_header_t *h, ngx_chain_t *in)
{
 for(n = 0; n < evhs->nelts; ++n, ++evh) {

        /*/*amf-->ngx_rtmp_amf_message_handler
         *standard protocol-->ngx_rtmp_protocol_message_handler
         *user protocol-->ngx_rtmp_user_message_handler*/
    /*eg:callee:h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_VIDEO]) 这种ngx_array_push cmcf->events */
        ngx_int_t ret = (*evh)(s, h, in);
    }
​​​​​​​}

ngx_rtmp_cmd_map 

ngx_int_t 
ngx_rtmp_amf_message_handler(ngx_rtmp_session_t *s,
        ngx_rtmp_header_t *h, ngx_chain_t *in)
{
    ngx_int_t //ngx_rtmp_amf_message_handler--ngx_rtmp_cmd_map--hash<->callback-->postconfiguration中的业务逻辑函数
ngx_rtmp_amf_message_handler(ngx_rtmp_session_t *s,
        ngx_rtmp_header_t *h, ngx_chain_t *in)
{
     ngx_int_t ret = (*ph)(s, h, in);
    ....
}
}


分发: map table 和 push event
ngx_rtmp_cmd_map
notes:信令和媒体分开:信令是relay, live 模块的publish 部分。媒体是live模块的live_av部分。
两部分没有调用关系.

rtmp交互逻辑

relay模块和对端服务器交互主要rtmp协议三次握手,connect,createStream,play/publish命令消息服务器.

Nginx rtmp 获取流有两种方式,一种是别的server push给自己流,一种是pull拉流 

 publish 

send streaming

        在完成以上步骤后客户端和服务器建立了一个网络流,接下来就可以传输媒体数据了。
大致流程如上图红色标注下面部分。
     一般来讲媒体数据分为两部分,一部分是meta元信息,另一部分是音视频数据。 
      首先传送的是meta元信息。客户端推送媒体,服务器处理如下       

Relay 模块

整体结构:  采用hash表+链表的结构;横向:同一个流名的链表: 用play串起来;纵向:不同流名用next串起来

pull  rtmp信令交互图:

1: 播放器端发起play

2: ngx_rtmp_relay_play()

3: ngx_rtmp_relay_pull() --主要建立pull请求, 将远程拉流的上下文和本地上下文放到链表中

    ngx_rtmp_relay_create_local_ctx()创建本地上下文

    ngx_rtmp_relay_create_remote_ctx()创建远端上下文

4: ngx_rtmp_relay_create_remote_ctx详解:  创建远端session, 开始rtmp信令交互

       1: ngx_rtmp_relay_create_connection  

        2: ngx_rtmp_init_session

注意:此时session中的flashver为“ngx-local-relay“

5: rtmp信令交互流程

核心函数: ngx_rtmp_relay_on_result主要用来接收对端服务端发送的amf消息包,而后按正常rtmp协议请求进行下一步交互,这个主要是当前服务端做为客户端发起远程rtmp请求流程

例如:   ngx_rtmp_client_handshake(发起握手)

         握手完成后调用回调函数: ngx_rtmp_relay_handshake_done

       ngx_rtmp_relay_send_connect:发起连接请求, 接着参考rtmp信令交互图

其他: 

stat:

static void
ngx_rtmp_process_stat_event_handler(ngx_event_t *ev)
{
  ......
	//5重循环遍历stat 每个client;each server  { each app  {each bucket {each stream {each client }}} }
    for (i = 0; i < cmcf->servers.nelts; ++i, ++cscf) { //for each server
        cacf = (*cscf)->applications.elts;
        for (n = 0; n < (*cscf)->applications.nelts; ++n, ++cacf) { // for each app
            ngx_str_t *pappname = &(*cacf)->name;
            lacf = (*cacf)->app_conf[ngx_rtmp_live_module.ctx_index];
		/*这个链表法:|
					 |__>->...  列是hash值,行是同一个hash值的不同的具体值; eg: hash %7 */
           /*nbuckets is:根据流名称进行hash时,bucket的数量;stream is 每个bucket中,对应ngx_rtmp_live_stream_t*数组*/
            for ( k = 0; k < (size_t)lacf->nbuckets; ++k ) { 
                for (stream = lacf->streams[k]; stream; stream = stream->next) { //for streams
                    for (ctx = stream->ctx; ctx; ctx = ctx->next, ++nclients) { //for clients
                       ....
}}}}}                }

Rtmp推流地址:rtmp://ip/live0/stream-name
对应的http-flv播放地址:http://ip/live0/stream-name 和 http://ip/flv0/stream-name
http-ts的配置方式和http-flv的配置原理完全相同。
对应的http-ts播放地址:http://ip/live0/stream-name

rtmp {
    server {
        listen 1935;
        application live0 {
            live on;
		}
}}
http {
    server {
        listen 80;
        location flv0 {
            flv_live 1935 app=live0;
        }
....}}

play2(播放)

和上面的play命令不同的是,play2命令可以在不改变播放内容时间轴的情况下切换到不同的比特率,服务器端会维护多种比特率的文件来供客户端使用play2命令来切换。

在这里插入图片描述

参考:

 push,pull config:Nginx-rtmp模块实现流媒体play、push、pull功能_莫失莫忘的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值