nginx_rtmp_module 之 ngx_rtmp_live_module模块

模块作用

直播模块代码 ngx_rtmp_live_module.c,主要作用是:当客户端推流或者拉流的时候,创建的rtmp session会加入到 live 模块的存储链表中。

模块配置命令

static ngx_command_t  ngx_rtmp_live_commands[] = {

    { ngx_string("live"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_flag_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, live),
      NULL },
    // 表示开启直播

    { ngx_string("stream_buckets"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_str_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, nbuckets),
      NULL },
    // 录制流名hash桶的大小

    { ngx_string("buffer"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_msec_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, buflen),
      NULL },
	// 设置默认缓冲区长度。通常客户端set_buflen在播放之前发送RTMP 命令,并重置此设置。默认是1000 ms。
    
    { ngx_string("sync"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_rtmp_live_set_msec_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, sync),
      NULL },
    // 同步音频和视频流。如果订阅者带宽不足以以发布者速率接收数据,则服务器会丢弃一些帧。这就导致了同步问题。当时间戳差异超过sync参数指定的值时,将发送一个绝对帧来修复它。默认值是300ms。
    
    { ngx_string("interleave"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_flag_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, interleave),
      NULL },
	// 切换交错模式。在这种模式下,音频和视频数据在相同的RTMP块流上传输。默认为关闭。
    
    { ngx_string("wait_key"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_flag_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, wait_key),
      NULL },
	// 使视频流开始于关键帧。在某些情况下才会触发
    
    { ngx_string("wait_video"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_flag_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, wait_video),
      NULL },

    { ngx_string("publish_notify"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_flag_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, publish_notify),
      NULL },

    { ngx_string("play_restart"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_flag_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, play_restart),
      NULL },

    { ngx_string("idle_streams"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_conf_set_flag_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, idle_streams),
      NULL },
    // 如果关闭,nginx-rtmp会阻止订阅用户连接到空闲/不存在的直播流,并在流发布者断开连接时断开所有订阅用户。默认为开启。

    { ngx_string("drop_idle_publisher"),
      NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1,
      ngx_rtmp_live_set_msec_slot,
      NGX_RTMP_APP_CONF_OFFSET,
      offsetof(ngx_rtmp_live_app_conf_t, idle_timeout),
      NULL },
    // 在指定时间内删除已空闲(无音频/视频数据)的发布者连接。默认为关闭。注意,这仅在连接处于发布模式(在发送发布命令之后)时有效。

      ngx_null_command
};

代码流程模块

1. 定义live_module 模块,加载模块的时候,会调用相应的函数进行初始化操作
 

static ngx_rtmp_module_t  ngx_rtmp_live_module_ctx = {
    NULL,                                   /* preconfiguration */
    ngx_rtmp_live_postconfiguration,        /* postconfiguration */
    NULL,                                   /* create main configuration */
    NULL,                                   /* init main configuration */
    NULL,                                   /* create server configuration */
    NULL,                                   /* merge server configuration */
    ngx_rtmp_live_create_app_conf,          /* create app configuration */
    ngx_rtmp_live_merge_app_conf            /* merge app configuration */
};

2. 配置文件初始化

static void * ngx_rtmp_live_create_app_conf(ngx_conf_t *cf)
{
    ngx_rtmp_live_app_conf_t      *lacf;

    // 从pool内存池中分配 ngx_rtmp_live_app_conf_t 对象
    lacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_live_app_conf_t));
    if (lacf == NULL) {
        return NULL;
    }

    lacf->live = NGX_CONF_UNSET;
    lacf->nbuckets = NGX_CONF_UNSET;
    lacf->buflen = NGX_CONF_UNSET_MSEC;
    lacf->sync = NGX_CONF_UNSET_MSEC;
    lacf->idle_timeout = NGX_CONF_UNSET_MSEC;
    lacf->interleave = NGX_CONF_UNSET;
    lacf->wait_key = NGX_CONF_UNSET;
    lacf->wait_video = NGX_CONF_UNSET;
    lacf->publish_notify = NGX_CONF_UNSET;
    lacf->play_restart = NGX_CONF_UNSET;
    lacf->idle_streams = NGX_CONF_UNSET;

    return lacf;
}

3. 解析配置文件,如果配置文件没有配置指定命令,则取默认值,配置值则直接赋值

static char *
ngx_rtmp_live_merge_app_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_rtmp_live_app_conf_t *prev = parent;
    ngx_rtmp_live_app_conf_t *conf = child;

    ngx_conf_merge_value(conf->live, prev->live, 0);
    ngx_conf_merge_value(conf->nbuckets, prev->nbuckets, 1024);
    ngx_conf_merge_msec_value(conf->buflen, prev->buflen, 0);
    ngx_conf_merge_msec_value(conf->sync, prev->sync, 300);
    ngx_conf_merge_msec_value(conf->idle_timeout, prev->idle_timeout, 0);
    ngx_conf_merge_value(conf->interleave, prev->interleave, 0);
    ngx_conf_merge_value(conf->wait_key, prev->wait_key, 1);
    ngx_conf_merge_value(conf->wait_video, prev->wait_video, 0);
    ngx_conf_merge_value(conf->publish_notify, prev->publish_notify, 0);
    ngx_conf_merge_value(conf->play_restart, prev->play_restart, 0);
    ngx_conf_merge_value(conf->idle_streams, prev->idle_streams, 1);

    conf->pool = ngx_create_pool(4096, &cf->cycle->new_log);
    if (conf->pool == NULL) {
        return NGX_CONF_ERROR;
    }

    conf->streams = ngx_pcalloc(cf->pool,
            sizeof(ngx_rtmp_live_stream_t *) * conf->nbuckets);

    return NGX_CONF_OK;
}

4. ngx_rtmp_live_av:音视频数据到来的时候会回调ngx_rtmp_live_av,进行处理数据
   ngx_rtmp_live_publish onpublish 时间回调此函数
   ngx_rtmp_live_play  onplay 事件回调此函数
   ngx_rtmp_live_close_stream 流关闭回到次函数

5. 当客户端推流或者拉流,会通过ngx_rtmp_live_join,把推流或者拉流的rtmp session 加入到流的hash 桶中,hash桶的大小可以通过配置,如果发生hash 冲突,则通过桶对应的链表进行解决,访问的时候通过name进行比较确定是哪一路stream。下面一图表示流的存储数据结构


6. 超时会断开流

static void
ngx_rtmp_live_idle(ngx_event_t *pev)
{
    ngx_connection_t           *c;
    ngx_rtmp_session_t         *s;

    c = pev->data;
    s = c->data;

    ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                  "live: drop idle publisher");

    ngx_rtmp_finalize_session(s);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/251813.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】键盘高级操作技巧

命令行最为珍视的目标之一就是懒惰:用最少的击键次数来完成最多的工作。另一个目标是你的手指永 远不必离开键盘,永不触摸鼠标。因此,我们有必要了解一些键盘操作,使我们用起来更加的迅速和高效。 移动光标 在前面介绍过上下左右…

JVM-2-对象

对象创建 当Java虚拟机遇到一条字节码new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。 为对象分配空间…

visual Studio MFC 平台实现图片的傅里叶变换

图片的傅里叶变换 本文主要讲解傅里叶变换的基本数学概念与物理概念,并本文使用visual Studio MFC 平台实现对傅里叶变换在图片上进行了应用。 一、傅里叶变换的原理 在这里推荐一篇讲得非常形象的文章通俗讲解:图像傅里叶变换 1.1 傅里叶变换原理的说明…

C++ 二叉搜索树(BST)的实现(非递归版本与递归版本)与应用

C 二叉搜索树的实现与应用 一.二叉搜索树的特点二.我们要实现的大致框架三.Insert四.InOrder和Find1.InOrder2.Find 五.Erase六.Find,Insert,Erase的递归版本1.FindR2.InsertR3.EraseR 七.析构,拷贝构造,赋值运算符重载1.析构2.拷贝构造3.赋值运算重载 八.Key模型完整代码九.二…

Prometheus 监控笔记(1):你真的会玩监控吗?

认识Prometheus Prometheus 是一种开源的系统和服务监控工具,最初由 SoundCloud 开发,后来成为继 Kubernetes 之后云原生生态系统中的一部分。在 Kubernetes 容器管理系统中,通常会搭配 Prometheus 进行监控,同时也支持多种 Expo…

股票价格预测 | Python实现基于ARIMA和LSTM的股票预测模型(含XGBoost特征重要性衡量)

文章目录 效果一览文章概述模型描述源码设计效果一览 文章概述 Python实现基于ARIMA和LSTM的股票预测模型(Stock-Prediction) Data ExtractionFormatting data for time seriesFeature engineering(Feature Importance using X

2023NEFU实习项目解析 - 中俄贸易供需服务平台

文章目录 项目概述项目初始化搭建项目初始框架配置Tomcat建立项目数据库编写统一返回类及其工具类编写数据库工具类通过Filter解决Response返回中文乱码问题使用Filter解决权限校验问题 项目主干开发用户登录企业管理(分页查询原生实现)上传VIP申请书模板…

【ArkTS】生命周期

页面生命周期 通常Entry修饰的组件称为页面,其拥有页面生命周期 onPageShow:页面每次显示时触发。onPageHide:页面每次隐藏时触发(通常是路由跳转到其他页面了)。onBackPress:当用户点击返回按钮时时触发…

【LeetCode刷题-哈希表】--187.重复的DNA序列

187.重复的DNA序列 本题就是找到长度为10的字符出现次数大于2的 子串序列 方法&#xff1a;使用哈希表 class Solution {public List<String> findRepeatedDnaSequences(String s) {List<String> ans new ArrayList<String>();HashMap<String,Integer&g…

GitLab下载地址是127.0.0.1如何修改ip

问题&#xff1a; 在下图位置之前我的ip是127.0.0.1&#xff0c;那我是如何修改的呢&#xff1f;请看下文 解决方案&#xff1a; 配置 GitLab站点 Url和端口号 GitLab 默认的配置文件路径是 /etc/gitlab/gitlab.rb # 修改配置文件 $ sudo vi /etc/gitlab/gitlab.rb 默认的站…

【lesson14】MySQL表的基本查询retrieve(读取)1

文章目录 表的基本操作介绍retrieveselect列建表基本测试 where子句建表基本测试 表的基本操作介绍 CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; retrieve select列 建表 基本测试 插入数据 全列查询 …

【人工智能】实验三 A*算法求解八/十五数码问题实验与基础知识

实验三 A*算法求解八数码问题实验 实验目的 熟悉和掌握启发式搜索的定义、估价函数和算法过程&#xff0c;并利用A*算法求解N数码难题&#xff0c;理解求解流程和搜索顺序。 实验内容 以8数码问题和15数码问题为例实现A*算法的求解程序&#xff08;编程语言不限&#xff09…

Redis知识详解(超详细)

1. 背景 Redis是由意大利人Antirez&#xff08;Salvatore Sanfilippo&#xff09;在2009年创造的开源内存数据结构存储系统。Redis的名字来自意大利语“Repubblica di Redis”&#xff0c;意思是“基于字典的共和国”。它是一个基于内存的键值对存储系统&#xff0c;具有快速、…

Leetcode 491 递增子序列

题意理解&#xff1a; 输入&#xff1a;nums [4,6,7,7] 输出&#xff1a;[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]] 这里不止要找一个子序列&#xff0c;还要元素保证其在原来的集合中的前后顺序&#xff0c;且应为增序。 为保证一个增序序列&#xff0c;…

移动端Vant中的Calendar日历增加显示农历(节日、节气)功能

核心&#xff1a; 使用 js-calendar-converter 库实现 npm地址&#xff1a;js-calendar-converter 内部使用原生calendar.js&#xff0c; 中国农历&#xff08;阴阳历&#xff09;和西元阳历即公历互转JavaScript库&#xff0c;具体实现感兴趣的可自行查看其实现源码。 原日…

【人工智能】实验四:遗传算法求函数最大值实验与基础知识

实验四&#xff1a;遗传算法求函数最大值实验 实验目的 熟悉和掌握遗传算法的原理、流程和编码策略&#xff0c;并利用遗传算法求解函数优化问题&#xff0c;理解求解流程并测试主要参数对结果的影响。 实验内容 采用遗传算法求解函数最大值。 实验要求 1. 用遗传算法求解…

扁平化菜单功能制作

网页效果&#xff1a; HTML部分&#xff1a; <body><ul class"nav"><li><a href"javascript:void(0);">菜单项目一</a><ul><li>子菜单项01</li><li>子菜单项02</li><li>子菜单项03<…

【C++】optional的使用(一)

这篇文章介绍下C17引入的std::optional 为什么要有 optional 一般来说&#xff0c;如果想要一个函数返回“多个”值&#xff0c;C程序员倾向于使用结构体/类完成这个操作。即定义一个通用的结构体&#xff0c;在函数内部完成装填&#xff0c;然后返回一个实例化的结构体。 #…

解决PP材质粘合问题用PP专用UV胶水

PP材料已经广泛应用于各行各业&#xff0c;在粘接中会有不同的问题需求&#xff0c;那么使用专用于PP的UV胶水可能是解决PP材质粘合问题的一种有效方法。 主要在于&#xff1a;UV胶水在紫外线照射下可以快速固化&#xff0c;形成坚固的连接。所以使用PP专用UV胶水时可以考虑&am…

oracle Job 定时任务

目录 介绍&#xff1a; 优点&#xff1a; 缺点&#xff1a; 使用场景&#xff1a; --查看定时任务 --查询存储过程 案例&#xff1a; --创建一个名为t_oracle_job的表 在创建定时任务时&#xff0c;各个参数的含义如下&#xff1a; 1. job_name&#xff1a…