我们介绍最简单的rtmp直播流程

概括

  1. 通过ngx_rtmp_module中的配置ngx_rtmp_block函数去建立对应的ngx_listening_t对象,并且将回调设置为ngx_rtmp_init_connection函数
  2. 在ngx_rtmp_init_connection接受到回调后开始调用ngx_rtmp_handshake握手,更改连接读的回调:ngx_rtmp_handshake_recv,写回调:ngx_rtmp_handshake_send,开始进行rtmp握手协议。
  3. 握手完毕后调用ngx_rtmp_cycle,开始进入接受rtmp的message阶段,读回调设置为ngx_rtmp_recv,写回调设置为ngx_rtmp_send。
  4. 收到一个rtmp的message进如ngx_rtmp_recv,收到不同的chunk后封装成message。调用ngx_rtmp_receive_message处理一个完整的ngx_rtmp_receive_message。在ngx_rtmp_receive_message中根据message的类型调用不同模块各自收到的回调
  5. (我们这边就讲音视频的回调,别的都是类似的)在ngx_rtmp_live_module中设置了一个音视频接受的回调ngx_rtmp_live_av,接收到音视频的数据后会调用这个函数。通过ngx_rtmp_prepare_message将一个message进行拆成一个一个chunk。最后调用ngx_rtmp_send将所有订阅一个一个传入。这样就结束了接受到发送的流程。
  6. 在一个用户需要播放的情况下,在解析到cmd是play的时候,回调用cmd的play回调链。同样也是在ngx_rtmp_live_module模块中。把播放的连接放入到对应的流stream后面。

开始监听

rtmp在一开始解析配置的时候会调用ngx_rtmp_optimize_servers函数用于向event中放入需要监听ip和端口,如果向具体了解一个链接怎么建立的可以参考上一篇文章nginx各个模块的监听怎么建立。设置了回调为ngx_rtmp_init_connection函数。

        while (i < last) {/* 省略无关代码 *//*这里外层有一个循环,为所有配置创建一个对应的监听*/ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen);if (ls == NULL) {return NGX_CONF_ERROR;}ls->addr_ntop = 1;ls->handler = ngx_rtmp_init_connection;}

握手

当接受到一个链接时候回调用ngx_rtmp_init_connection,并且把连接传入ngx_connection_t。把ngx_connection_t封装成一个ngx_rtmp_session_t后,开始调用rtmp协议的握手ngx_rtmp_handshake函数,这里把连接的读取和写入函数都改成了握手对应的函数,握手分为很多步骤,可以详细了解rtmp协议。

void
ngx_rtmp_handshake(ngx_rtmp_session_t *s)
{ngx_connection_t           *c;c = s->connection;/*修改读写的回调*/c->read->handler =  ngx_rtmp_handshake_recv;c->write->handler = ngx_rtmp_handshake_send;ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,"handshake: start server handshake");s->hs_buf = ngx_rtmp_alloc_handshake_buffer(s);s->hs_stage = NGX_RTMP_HANDSHAKE_SERVER_RECV_CHALLENGE;/*开始读取对端的数据,这里就涉及到rtmp协议的具体内容了*/ngx_rtmp_handshake_recv(c->read);
}

进入rtmp的消息循环

在握手完毕后,会调用ngx_rtmp_handshake_done进入ngx_rtmp_cycle的循环

static void
ngx_rtmp_handshake_done(ngx_rtmp_session_t *s)
{ngx_rtmp_free_handshake_buffers(s);ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,"handshake: done");if (ngx_rtmp_fire_event(s, NGX_RTMP_HANDSHAKE_DONE,NULL, NULL) != NGX_OK){ngx_rtmp_finalize_session(s);return;}ngx_rtmp_cycle(s);
}

并且把对应的读写函数设置为ngx_rtmp_recv和ngx_rtmp_send。直接开始读取第一个message。

voidngx_rtmp_cycle(ngx_rtmp_session_t *s){ngx_connection_t           *c;c = s->connection;/*修改对应的回调*/c->read->handler =  ngx_rtmp_recv;c->write->handler = ngx_rtmp_send;s->ping_evt.data = c;s->ping_evt.log = c->log;s->ping_evt.handler = ngx_rtmp_ping;ngx_rtmp_reset_ping(s);/*读取第一个message包*/ngx_rtmp_recv(c->read);}

处理message

当开始读取message后,rtmp module会把一个一个chunk封装成message,然后根据对应message的type类型,调用各个回调函数。
在ngx_rtmp_recv会调用ngx_rtmp_receive_message函数处理一个封装完成的message

static void
ngx_rtmp_recv(ngx_event_t *rev)
{/*省略和rtmp具体协议相关封装message代码*//*s是连接,h是message的报头,head是message报文*/if (ngx_rtmp_receive_message(s, h, head) != NGX_OK) {ngx_log_error(NGX_LOG_WARN, c->log, 0,"rtmp recv receive message failed");ngx_rtmp_finalize_session(s);return;}
}

在ngx_rtmp_receive_message中会根据message的type然后调用不同的回调函数,后面会以ngx_rtmp_live_module模块为例注册回调

ngx_int_t
ngx_rtmp_receive_message(ngx_rtmp_session_t *s,ngx_rtmp_header_t *h, ngx_chain_t *in)
{/*省略无关代码*//*h->type是message类型,evhs是各个module在初始化时候注册的回调函数数组*/evhs = &cmcf->events[h->type];evh = evhs->elts;/*调用各个回调*/for(n = 0; n < evhs->nelts; ++n, ++evh) {if (!evh) {continue;}switch ((*evh)(s, h, in)) {case NGX_ERROR:return NGX_ERROR;case NGX_DONE:return NGX_OK;}}
}

ngx_rtmp_live_module是怎么注册message类型的回调函数的

static ngx_int_tngx_rtmp_live_postconfiguration(ngx_conf_t *cf){/*省略无关代码*//* 在配置的时候注册对应的回调函数 */h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]);*h = ngx_rtmp_live_av;h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_VIDEO]);*h = ngx_rtmp_live_av;
}

发送message

这里举音视频message的例子,当来了一个音视频的message时会最终调用ngx_rtmp_live_av函数回调,并且在ngx_rtmp_live_av中遍历所有订阅者,调用ngx_rtmp_prepare_message准备数据,然后一个一个调用ngx_rtmp_send_message函数发送数据。

static ngx_int_t
ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h,ngx_chain_t *in)
{/*省略无关代码*//*pctx代表每个订阅者,pctx->next表示下一个订阅者*/    for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) {/*这里简化代码*//*s 发送的session,ch表示这次要发送message保存的报头*//*lh 最后一个发送message报头,rpkt这次要发送的message的报文*/ngx_rtmp_prepare_message(s, &ch, &lh, rpkt);ss = pctx->session;/*ss是具体的订阅者,rpkt是发送的数据包,prio是这个包的优先级*/ngx_rtmp_send_message(ss, rpkt, prio);}
}

播放加入到对应的流中

在一个客户端发送play的cmd message的时候,表示他需要去播放一路流。这个时候会触发ngx_rtmp_live_module中ngx_rtmp_play回调。
下面是ngx_rtmp_live_module注册回调的配置。

static ngx_int_tngx_rtmp_live_postconfiguration(ngx_conf_t *cf){/* 省略无关代码 */next_play = ngx_rtmp_play;ngx_rtmp_play = ngx_rtmp_live_play;
}

在nginx中的ngx_rtmp_live_play中调用ngx_rtmp_live_join将session加入到对应的流中

static ngx_int_t
ngx_rtmp_live_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v)
{/*......*//* 加入对应的流中 */ngx_rtmp_live_join(s, v->name, 0)
}

在ngx_rtmp_live_join中采用头插法加入到流中

static void
ngx_rtmp_live_join(ngx_rtmp_session_t *s, u_char *name, unsigned publisher)
{/*......*/ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module);if (ctx && ctx->stream) {ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,"live: already joined");return;}if (ctx == NULL) {ctx = ngx_palloc(s->connection->pool, sizeof(ngx_rtmp_live_ctx_t));ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_live_module);}ngx_memzero(ctx, sizeof(*ctx));/*可以看出ctx是属于当前这个session*/ctx->session = s;ctx->stream = *stream;ctx->publishing = publisher;/*将当前session ctx的next指向stream的第一个ctx*/ctx->next = (*stream)->ctx;/*重置stream第一个ctx为当前的ctx,链表的头插法*/(*stream)->ctx = ctx;
}

ngx_rtmp_module直播流程相关推荐

  1. 音视频直播流程及常见视频流协议介绍

    音视频直播流程介绍 常见视频流协议介绍 HLS HLS是苹果公司实现的基于 HTTP 的流媒体传输协议,全称 HTTP Live Streaming,可支持流媒体的直播和点播,主要应用在 iOS 系统 ...

  2. 首席新媒体运营黎想教程:可复用的社群运营+直播流程

    2020年因疫情的影响,许多企业都被迫转型线上,甚至于一直坚持只做传统线下的一些公司都为了能寻找新的机遇,不被时代所淘汰,开始接触线上,试图从线上开辟一条新的商业模式. 我们常规所说的一些线上平台,大 ...

  3. Android 直播 APP实现直播流程

    Android 直播 APP实现直播流程 直播本质 1. 主播端采集音视频 2. 视频处理(美颜,水印) 3. 视频编解码 视频编码框架 视频编码技术 压缩方式 视频编解码和压缩时的关键知识点 4. ...

  4. 首席新媒体黎想教程:可复用的社群运营,加直播流程!

    2020年许多企业都被迫转型线上,甚至一直坚持只做传统线下的一些公司都为了能寻找新的机遇.不被时代所淘汰,开始接触线上,试图从线上开辟一条新的商业模式. 我们常规所说的一些线上平台,大致可以分为:网站 ...

  5. 抖音直播前需要准备什么;超详细直播流程步骤;丨国仁网络资讯

    直播已经成为2020年商家营销的一个必要渠道,随着移动互联网发展日益壮大,全国各大行业基本上已经普及了网络化,直播行业已经成为炙手可热的话题,其中又以抖音为最. 很多新人主播刚开始直播都会感觉自己好紧 ...

  6. 没出货和人气可能问题在直播流程上

    什么是直播流程呢,直播流程是指直播从开始到下播的各项环节安排的程序. 一个好的直播流程,能让你在镜头前始终充满活力,井井有条的展示和引导用户购买商品,还可以提升直播间的人气. 最近我通过短鱼儿查看各平 ...

  7. 直播流程以及常见问题

    直播流程以及常见问题 腾讯RTMP SDK支持哪些功能和协议? 腾讯视频云 RTMP SDK 支持推流.直播和点播三个功能: 推流支持RTMP发布协议,并包含硬件加速,美颜滤镜,带宽适应,清晰度调整等 ...

  8. 直播平台搭建|实现完整直播流程,考验直播平台性能

    直播平台搭建的意义是为了实现完整的直播流程: 前处理: 最重要的部分是实时GPU渲染美感,前处理中还要去除水印.时间戳等,这也是在直播平台必要的防范措施.实时美颜本身就相当考验APP厂商的技术经济实力 ...

  9. iOS 直播流程概述

    写在前面 本文目的在于带大家了解一场直播背后,需要经历哪些阶段,以及每个阶段都做了哪些工作,才能够把主播的声音画面送到观众的面前.我们把直播的流程划分为以下六个阶段: 采集 处理 编码 封装 网络传输 ...

最新文章

  1. 链表-删除链表中的重复元素
  2. golang 命名规范和开发规范
  3. python【蓝桥杯vip练习题库】—Huffuman树
  4. 为SSIS编写自定义数据流组件(DataFlow Component)之进阶篇:自定义编辑器
  5. ssl提高组周六模拟赛【2019.3.2】
  6. iOS 计算文字宽度的一个细节
  7. Apache Flink OLAP引擎性能优化及应用
  8. 我的职业规划,大家给点意见吧!
  9. 在c语言程序中可把整型数,C语言程序设计(2).doc
  10. vsftpd配置好防火墙后从网页登录ftp却无法访问此页面
  11. Civil3D二次开发常见问题总结
  12. QT递归获取指定目录下的所有文件
  13. 如何对Firefox拓展程序进行修改
  14. java-pdf转word
  15. mysql 时间查询_MYSQL按时间段查询语句大全
  16. struts的增删查改
  17. SpringMVC:生成Excel和PDF
  18. HDP 2.6.5配置yarn的CGroups
  19. 【STL】C++ STL超全总结
  20. SAP工具箱 通用条件/加点率配置

热门文章

  1. MTK Combo Chip常用调试命令
  2. GitHub 标星 4.9k,李笑来开源的英语学习课
  3. 秀米的对话框格子可以变大吗_更新丨秀米图文可以一键兼容多格式发布到其他平台了!...
  4. 20210505 秀米导入已发布微信推送的所有内容
  5. 前后端跨语言RSA加解密和签名验证实现(js+python)
  6. mongoose用模型更新不了,因为模型对象中默认带有_id会提示errmsg: “Performing an update on the path ‘_id‘ would modify the i
  7. Python爬取的微信好友信息里我看到了自律 | CSDN博文精选
  8. NameError: name ‘weights‘ is not defined
  9. java泛型的上界下界
  10. 无人船水下地形测量的应用及优势