深入理解nginx mp4流媒体模块[上]

目录

  • 1. 引言
  • 2. 配置
  • 3. 源码分析
    • 3.1 配置指令
      • 3.1.1 mp4
      • 3.1.2 mp4_buffer_size
      • 3.1.3 mp4_max_buffer_size
      • 3.1.4 mp4_start_key_frame
    • 3.2 MP4的请求处理过程
      • 3.2.1 预处理
      • 3.2.2 找到并打开本地mp4文件
      • 3.2.3 解析请求参数
      • 3.2.4 MP4文件的处理

1. 引言

  在当今数字化时代,视频已成为互联网上最主要的内容形式之一。NGINX作为一款高性能的Web服务器和反向代理服务器,提供了强大的MP4模块,用于优化MP4视频的点播传输功能,并支持播放器的任意拖拽功能。本文将通过通过源码分析深入探讨NGINX MP4模块的实现源码,介绍其功能和实现原理。

NGINX MP4模块的作用和优势
  NGINX MP4模块的主要作用是优化MP4视频的点播传输功能,提供快速启动和流畅播放的体验。它通过减少客户端和Web服务器之间的交互,降低额外数据消耗,显著减少流媒体播放的启动时间。以下是NGINX MP4模块的优势:

  • 快速启动时间:通过预读取视频文件的元数据,NGINX MP4模块实现了快速的启动时间。用户请求播放视频时,只需加载视频的元数据,无需等待整个视频文件加载完毕。
  • 支持任意拖拽功能:现代浏览器在Web服务器支持HTTP Range请求的情况下,可以通过MP4模块实现视频的任意拖拽功能,提供更好的用户体验。
  • 减少数据传输:MP4模块减少了不必要的HTTP请求,通过边播边加载的方式为用户提供视频流,减少额外的性能消耗。

NGINX MP4模块的实现原理
  NGINX MP4模块通过读取和解析MP4视频文件的元数据,实现优化的点播传输。它预读取视频文件的元数据,包括视频的时长、编码信息、音频信息等,并将这些信息缓存到内存中。当用户请求播放视频时,NGINX MP4模块直接从内存中获取元数据,根据客户端的请求,按需传输视频片段,实现快速启动和流畅播放的效果。

2. 配置

  要使用NGINX MP4模块,需要在NGINX的配置文件中进行相应的配置。以下是一个简单的配置示例:

location /videos/ {root html;mp4;                     # 开启mp4流媒体功能mp4_buffer_size 1m;      # mp4 moov元数据缓存的默认空间大小mp4_max_buffer_size 10m; # mp4 moov元数据缓存的最大空间
}

  通过以上配置,就可以通过 curl模拟播放器访问了。例如:


#从头开始播放
curl "http://127.0.0.1/videos/test.mp4"                     #从第100s播放到200s
curl "http://127.0.0.1/videos/test.mp4?start=100&end=200"   

  这里需要强调的是,对于一些特别大的mp4文件,可能moov元数据的大小就超过了mp4_max_buffer_size,会导致nginx报错的情况,但是如果设置太大,特别是mp4_buffer_size设置得太大,就会使得nginx消耗太多的内存,引起其他问题。因此,需要预先对moov大小有一个预估。

3. 源码分析

3.1 配置指令

3.1.1 mp4

{ ngx_string("mp4"),NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,ngx_http_mp4,0,0,NULL },

 &emps;这个指令开启mp4流媒体功能,从以上定义可以知道这个指令只能在location中配置。

  在ngx_http_mp4配置指令解析函数中,设置了ngx_http_mp4_handler回调函数,如下:

static char *
ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ngx_http_core_loc_conf_t  *clcf;clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);clcf->handler = ngx_http_mp4_handler;return NGX_CONF_OK;
}

  该回调函数会在NGX_HTTP_CONTENT_PHRASE阶段回调这个函数进行mp4的处理。

3.1.2 mp4_buffer_size

{ ngx_string("mp4_buffer_size"),NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,ngx_conf_set_size_slot,NGX_HTTP_LOC_CONF_OFFSET,offsetof(ngx_http_mp4_conf_t, buffer_size),NULL },

  这个指令定义了moov数据缓冲区的默认大小,可以在http/server/location中配置。

3.1.3 mp4_max_buffer_size

{ ngx_string("mp4_max_buffer_size"),NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,ngx_conf_set_size_slot,NGX_HTTP_LOC_CONF_OFFSET,offsetof(ngx_http_mp4_conf_t, max_buffer_size),NULL },

  这个指令定义了moov数据缓冲区的最大空间,可以在http/server/location中配置。

3.1.4 mp4_start_key_frame

{ ngx_string("mp4_start_key_frame"),NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,ngx_conf_set_flag_slot,NGX_HTTP_LOC_CONF_OFFSET,offsetof(ngx_http_mp4_conf_t, start_key_frame),NULL },

  这个指令设置是否将视频起始帧对齐到最近的关键帧开始发送数据。

3.2 MP4的请求处理过程

  下面以ngx_http_mp4_handler函数为分析对象,说明MP4的请求处理过程。

3.2.1 预处理

  • 过滤非GET/HEAD请求。
if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {return NGX_HTTP_NOT_ALLOWED;
}
  • 取消接收客户端请求的http body部分。
 rc = ngx_http_discard_request_body(r);

3.2.2 找到并打开本地mp4文件

  • 获取mp4文件的完整路径
last = ngx_http_map_uri_to_path(r, &path, &root, 0);
if (last == NULL) {return NGX_HTTP_INTERNAL_SERVER_ERROR;
}log = r->connection->log;path.len = last - path.data;
  • 打开mp4文件
of.read_ahead = clcf->read_ahead;
of.directio = NGX_MAX_OFF_T_VALUE;
of.valid = clcf->open_file_cache_valid;
of.min_uses = clcf->open_file_cache_min_uses;
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;/*用于设置NGINX服务器是否允许访问符号链接文件的功能。当启用该功能时,NGINX将拒绝通过符号链接文件访问文件系统中的文件。
*/
if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {return NGX_HTTP_INTERNAL_SERVER_ERROR;
}if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)!= NGX_OK)
{
......
}

3.2.3 解析请求参数

  从http请求的querystring部分提取到start和end参数,这两个参数的单位都是秒。

if (r->args.len) {if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) {/** A Flash player may send start value with a lot of digits* after dot so a custom function is used instead of ngx_atofp().*/start = ngx_http_mp4_atofp(value.data, value.len, 3);}if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) {end = ngx_http_mp4_atofp(value.data, value.len, 3);if (end > 0) {if (start < 0) {start = 0;}if (end > start) {length = end - start;}}}
}

3.2.4 MP4文件的处理

if (start >= 0) {r->single_range = 1;/* 分配并初始化mp4处理上下文 */mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t));if (mp4 == NULL) {return NGX_HTTP_INTERNAL_SERVER_ERROR;}mp4->file.fd = of.fd;mp4->file.name = path;mp4->file.log = r->connection->log;mp4->end = of.size;mp4->start = (ngx_uint_t) start;mp4->length = length;mp4->request = r;/* 加载并调整mp4的moov元信息帧索引 */switch (ngx_http_mp4_process(mp4)) {case NGX_DECLINED:if (mp4->buffer) {ngx_pfree(r->pool, mp4->buffer);}ngx_pfree(r->pool, mp4);mp4 = NULL;break;case NGX_OK:r->headers_out.content_length_n = mp4->content_length;break;default: /* NGX_ERROR */if (mp4->buffer) {ngx_pfree(r->pool, mp4->buffer);}ngx_pfree(r->pool, mp4);return NGX_HTTP_INTERNAL_SERVER_ERROR;}
}

  以下对ngx_http_mp4_file_t的结构定义进行说明:

typedef struct {ngx_file_t            file;              # mp4文件对象u_char               *buffer;            # 用于mp4分析的缓冲区u_char               *buffer_start;      # buffer空闲的起始位置u_char               *buffer_pos;        # buffer中可用于分析的起始位置u_char               *buffer_end;        # buffer中可用于分析的结束位置size_t                buffer_size;       # mp4分析缓冲区buffer的大小off_t                 offset;            # 当前mp4文件读取的偏移量off_t                 end;               # 当前mp4文件的文件大小off_t                 content_length;    # 最终发送给客户端响应的内容长度ngx_uint_t            start;             # 请求的起始偏移时间ngx_uint_t            length;            # 请求的视频时长uint32_t              timescale;         # mp4文件中设置的时间scale值ngx_http_request_t   *request;           # 对应当前的http request对象ngx_array_t           trak;              # mp4包含的track列表,引用traks,最多2ngx_http_mp4_trak_t   traks[2];          # mp4包含的track列表size_t                ftyp_size;         # ftyp atom的大小size_t                moov_size;         # moov atom的大小ngx_chain_t          *out;ngx_chain_t           ftyp_atom;         # 链接了ftyp_atom_buf的缓冲区链ngx_chain_t           moov_atom;         # 链接了moov_atom_buf的缓冲区链ngx_chain_t           mvhd_atom;         # 链接了mvhd_atom_buf的缓冲区链ngx_chain_t           mdat_atom;         # 链接了mdat_atom_buf的缓冲区链ngx_chain_t           mdat_data;         # 链接了mdat_data_buf的缓冲区链ngx_buf_t             ftyp_atom_buf;     # ftyp atom的缓冲区ngx_buf_t             moov_atom_buf;     # moov atom的缓冲区ngx_buf_t             mvhd_atom_buf;     # mvhd atom的缓冲区ngx_buf_t             mdat_atom_buf;     # mdat atom的缓冲区ngx_buf_t             mdat_data_buf;     # mdat atom的缓冲区u_char                moov_atom_header[8];u_char                mdat_atom_header[16];
} ngx_http_mp4_file_t;

<未完待续>
下接:深入理解nginx mp4流媒体模块[中]

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv9改进策略:卷积魔改 | DCNv2升级版本,助力检测

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a;在DCN的基础上&#xff0c;增加了2个创新点&#xff0c;分别是调制模块和使用多个调制后的DCN模块&#xff0c;从形成了DCN的升级版本——DCNv2 &#x1f4a1;&#x1f4a1;&#x1f4a1;如何使用&#xff1a…

红岩思维导图的制作软件,分享4款热门的!

红岩思维导图的制作软件&#xff0c;分享4款热门的&#xff01; 在当今信息爆炸的时代&#xff0c;思维导图作为一种有效的知识整理和思维拓展工具&#xff0c;受到了广大用户的青睐。红岩思维导图以其独特的风格和实用性&#xff0c;成为了许多人学习和工作中的得力助手。那么…

JavaScript中的行为委托和面向类的区别?

先复习一些原型链的知识&#xff1a; [[Prototype]] 机制是一种存在于一个对象上的内部链接&#xff0c;它指向一个其他对象。 在JavaScript中&#xff0c;每个对象都有一个原型对象&#xff08;prototype&#xff09;&#xff0c;当访问对象的属性或方法时&#xff0c;如果对象…

【SpringSecurity】基础入门

目录 权限管理什么是权限管理认证授权权限管理解决方案Shiro开发者自定义Spring Security Spring Security特性Spring、Spring Boot 和 Spring Security 三者的关系整体架构1.认证AuthenticationManagerAuthenticationSecurityContextHolder 2.授权AccessDecisionManagerAccess…

作为数据分析师,如何能把AI工具和数据分析工作更好的结合?

在当今信息爆炸的时代&#xff0c;数据已经成为企业、研究机构乃至个人决策的重要依据。然而&#xff0c;如何高效地处理、分析和解读这些数据&#xff0c;从而提炼出有价值的信息&#xff0c;却成为了一个亟待解决的问题。 幸运的是&#xff0c;随着人工智能技术的飞速发展&a…

刷好题,固基础-2

7-5 运动会 T公司的员工层级关系可以表示成一棵树&#xff0c;员工X是员工Y的直接领导&#xff0c;则在树中X是Y的父结点。公司拟组织一场运动会&#xff0c;但为了避免尴尬&#xff0c;每个员工都不想与自己的直接领导一起参赛。假定每个员工都对应一个权重&#xff08;领导的…

二叉树|450.删除二叉搜索树中的节点

力扣题目链接 class Solution { public:TreeNode* deleteNode(TreeNode* root, int key) {if (root nullptr) return root; // 第一种情况&#xff1a;没找到删除的节点&#xff0c;遍历到空节点直接返回了if (root->val key) {// 第二种情况&#xff1a;左右孩子都为空&…

使用AI 编写一个Mybatis SQL日志解析工具

使用AI 编写一个Mybatis SQL日志解析工具 背景 尝试使用智谱清言 AI 编写一个工具&#xff0c;将Mybatis SQL日志解析为可以执行的SQL语句。 操作 准备初始代码 首先网站上找了一个有BUG的简单的实现 https://blog.csdn.net/x541211190/article/details/107410409 用提示…

【WEEK4】 【DAY5】AJAX第二部分【中文版】

2024.3.22 Friday 接上文【WEEK4】 【DAY4】AJAX第一部分【中文版】 目录 8.4.Ajax异步加载数据8.4.1.新建User.java8.4.2.在pom.xml中添加lombok、jackson支持8.4.3.更改tomcat设置8.4.4.修改AjaxController.java8.4.5.新建test2.jsp8.4.5.1.注意&#xff1a;和WEB-INF平级&…

.NET Core教程:入门与实践实例

.NET Core教程&#xff1a;入门与实践实例 在信息技术飞速发展的今天&#xff0c;掌握一门高效的编程技术成为了每个开发者不可或缺的技能。在众多编程框架中&#xff0c;.NET Core以其跨平台、高性能和易扩展的特性&#xff0c;受到了广大开发者的青睐。本文将通过实例&#…

一文解析:固定电感器结构、作用及其与扼流圈和可变电感器的差异

固定电感器是一种电子元件又称固定线圈&#xff0c;用于在电路中产生固定的电感值。电感是指导致电流变化时产生电动势的能力&#xff0c;通常用亨利&#xff08;Henry&#xff09;作为单位。固定电感器的电感值是预先确定的&#xff0c;通常以特定的数值标识&#xff0c;例如1…

免疫荧光染色

每次要将手/样品伸进细胞培养箱&#xff0c;生物培养平台D 中时&#xff0c;都要喷洒酒精消毒。 以两个样品/两个培养基为例 从细胞培养箱&#xff08;37度&#xff0c;5%CO2浓度&#xff09;取出要染色的细胞&#xff1b;放在显微镜下观察&#xff0c;观察细胞是否趴壁以及细…

【正点原子FreeRTOS学习笔记】————(10)FreeRTOS时间管理

这里写目录标题 一、延时函数介绍&#xff08;了解&#xff09;二、延时函数解析&#xff08;熟悉&#xff09;三、延时函数演示实验&#xff08;掌握&#xff09; 一、延时函数介绍&#xff08;了解&#xff09; 相对延时&#xff1a;指每次延时都是从执行函数vTaskDelay()开始…

onnxruntime 中的 Gather 算子

上一篇文章中介绍了 Division by Invariant Integers using Multiplication 的原理&#xff0c;很多框架均才用该算法优化除法运算。onnxruntime 是已知实现中最为简洁的&#xff0c;因此本文结合 onnxruntime 的 Gather 实现进行介绍。 Gather 算子是一个索引类算子&#xff0…

Python(django)之单一接口展示功能前端开发

1、代码 建立apis_manage.html 代码如下&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>测试平台</title> </head> <body role"document"> <nav c…

S7-200 SMART 选型指南及详细技术参数

S7-200 SMART 选型指南 选型指南 硬件能力 功能 CPU外形结构与电源需求计算 直流安装 交流安装 电源需求与计算 S7-200 SMART CPU模块提供5VDC和24VDC电源&#xff1a; CPU有一个内部电源&#xff0c;用于为CPU、扩展模块、信号板提供电源和满足其他24 VDC用户电源需求。请使…

数据结构二叉树计算公式

这些是关于二叉树、完全二叉树、B-树以及树的深度和高度的一些基本概念和重要性质。让我们一一解读这些性质: 二叉树的计数公式:给定 n 个节点,可以构造的不同二叉树数量是 (\frac{(2n)!}{n! \cdot (n+1)!})。这是一个来自组合数学的结果,称为 Catalan 数。这个公式非常重要…

鸿蒙HarmonyOS应用开发之使用Node-API接口进行线程安全开发

场景介绍 napi_create_threadsafe_function是Node-API接口之一&#xff0c;用于创建一个线程安全的JavaScript函数。主要用于在多个线程之间共享和调用&#xff0c;而不会出现竞争条件或死锁。例如以下场景&#xff1a; 异步计算&#xff1a;如果需要进行耗时的计算或IO操作&a…

Scala介绍与环境搭建

Scala环境搭建与介绍 一、Scala环境搭建 1、环境准备与下载 2、验证Scala 3、IDEA新建项目&#xff0c;配置Scala&#xff0c;运行Hello world 二、Scala介绍 1、Scala 简介 2、Scala 概述 一、Scala环境搭建 1、环境准备与下载 JDK1.8 Java Downloads | Oracle 下载需求版本…

如何将python项目转变成deb安装包

先将python项目转变成可执行文件 1. 首先确保你的python项目可以正常执行 2.安装pyinstaller模块&#xff0c;pip install pyinstaller -i Simple Index 3.确定好你的项目的文件入口&#xff0c;也就是运行的文件.py 4. 开始打包成单文件&#xff0c;pyinstaller -F <第…