深入理解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文件的处理
深入理解nginx mp4流媒体模块[上]
深入理解nginx mp4流媒体模块[中]
深入理解nginx 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,最多2个ngx_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流媒体模块[中]
相关文章:
深入理解nginx mp4流媒体模块[上]
目录 1. 引言2. 配置3. 源码分析3.1 配置指令3.1.1 mp43.1.2 mp4_buffer_size3.1.3 mp4_max_buffer_size3.1.4 mp4_start_key_frame 3.2 MP4的请求处理过程3.2.1 预处理3.2.2 找到并打开本地mp4文件3.2.3 解析请求参数3.2.4 MP4文件的处理 深入理解nginx mp4流媒体模块[上] 深入…...

Go 之 Gin 框架
Gin 是一个 Go (Golang) 编写的轻量级 web 框架,运行速度非常快,擅长 Api 接口的高并发,如果项目的规模不大,业务相对简单,这个时候我们也推荐您使用 Gin,特别适合微服务框架。 简单路由配置 package mai…...

vue3+threejs新手从零开发卡牌游戏(二十一):添加战斗与生命值关联逻辑
首先将双方玩家的HP存入store中,stores/common.ts代码如下: import { ref, computed } from vue import { defineStore } from piniaexport const useCommonStore defineStore(common, () > {const _font ref() // 字体const p1HP ref(4000) // 己…...

Linux内核err.h文件分析
在阅读和编写内核相关的代码时,经常会看到IS_ERR、ERR_PTR等函数。这些函数在内核头文件的err.h中。以我服务器的代码为例,内核版本为5.15。 这个文件的代码如下: /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_ERR_H #define _L…...

Qt 富文本处理 (字体颜色大小加粗等)
Qt中支持HTML的控件有textEdit 、label 、textBrowser 。 接口:setHtml("Qt"); toHtml(). 文本样式设置 : 可分字设置 ,主要使用QTextCharFormat类进行文本样式设置。 示例: QTextCharFormat fmt; //粗体 fmt.setFontWeight…...

消息队列的七种经典应用场景
在笔者心中,消息队列,缓存,分库分表是高并发解决方案三剑客。 在职业生涯中,笔者曾经使用过 ActiveMQ 、RabbitMQ 、Kafka 、RocketMQ 这些知名的消息队列 。 这篇文章,笔者结合自己的真实经历,和大家分享…...

uniapp 微信小程序 canvas 手写板文字重复倾斜水印
核心逻辑 先将坐标系中心点通过ctx.translate(canvasw / 2, canvash / 2) 平移到canvas 中心,再旋转设置水印 假如不 translate 直接旋转,则此时的旋转中心为左上角原点,此时旋转示意如图所示 当translate到中心点之后再旋转,此…...
JavaScript如何制作轮播图
在JavaScript中实现轮播图可以通过多种方式,但最常见的方式是使用数组来存储图片,然后使用setInterval函数定期更改显示的图片。下面是一个简单的例子: 首先,你需要在HTML中设置一些用于显示图片的<img>标签,以…...

【面试经典150 | 动态规划】零钱兑换
文章目录 Tag题目来源解题思路方法一:动态规划 写在最后 Tag 【动态规划】【数组】 题目来源 322. 零钱兑换 解题思路 方法一:动态规划 定义状态 dp[i] 表示凑成总金额的最少硬币个数。 状态转移 从小到大枚举要凑成的金额 i,如果当前…...

什么是防火墙,部署防火墙有什么好处?
与我们的房屋没有围墙或界限墙一样,没有防护措施的计算机和网络将容易受到黑客的入侵,这将使我们的网络处于巨大的风险之中。因此,就像围墙保护我们的房屋一样,虚拟墙也可以保护和安全我们的设备,使入侵者无法轻易进入…...

学习鸿蒙基础(10)
目录 一、轮播组件 Swiper 二、列表-List 1、简单的List 2、嵌套的List 三、Tabs容器组件 1、系统自带tabs案例 2、自定义导航栏: 一、轮播组件 Swiper Entry Component struct PageSwiper {State message: string Hello Worldprivate SwCon: SwiperControl…...

阿里云对象存储OSS入门
阅读目录 一、阿里云OSS的使用 1、OSS是什么?2、OSS的使用 二、阿里云OSS的使用三、图床的搭建四:图床绑定阿里云OSS 编写不易,如果我的文章对你有帮助的话,麻烦小伙伴还帮忙点个赞再走! 如果有小伙伴觉得写的啰嗦&a…...

[幻灯片]软件需求设计方法学全程实例剖析-03-业务用例图和业务序列图
DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 pdf已上传至本号的CSDN资源,或到以下地址下载: http://umlchina.com/training/umlchina_03_bm.pdf...

ctfshow-web入门-xxe
什么是xxe? XXE,全称XML External Entity Injection,即XML外部实体注入。这是一种针对应用程序解析XML输入类型的攻击。当包含对外部实体的引用的XML输入被弱配置的XML解析器处理时,就会发生这种攻击。这种攻击通过构造恶意内容&…...

Docker数据卷挂载
一、容器与数据耦合的问题: 数据卷是虚拟的,不真实存在的,它指向文件中的文件夹 ,属主机文件系统通过数据卷和容器数据进行联系,你改变我也改变。 解决办法: 对宿主机文件系统内的文件进行修改,会立刻反应…...

QT_day4:对话框
1、完善对话框,点击登录对话框,如果账号和密码匹配,则弹出信息对话框,给出提示”登录成功“,提供一个Ok按钮,用户点击Ok后,关闭登录界面,跳转到其他界面 如果账号和密码不匹配&…...

矢量数据库:连接人工智能应用程序的数据复杂性与可用性的桥梁
关注我的公众号:Halo咯咯 简介 矢量数据库是一种专门设计的数据库,专注于高效地存储、管理和操作矢量数据。与传统数据库处理标量值(如数字、字符串、日期)不同,矢量数据库针对的是那些表现为多维数据点的向量…...
docker:can’t create unix socket /var/run/docker.sock: is a directory
docker:can’t create unix socket /var/run/docker.sock: is a directory 原因:docker.sock不能创建 解决方式: rm -rf /var/run/docker.sock 然后重新启动docker Docker是一种相对使用较简单的容器,我们可以通过以下几种方式获取信息&…...

Qt 图形视图 /图形视图框架坐标系统的设计理念和使用方法
文章目录 概述Qt 坐标系统图形视图的渲染过程Item图形项坐标系Scene场景坐标系View视图坐标系map坐标映射场景坐标转项坐标视图坐标转图形项坐标图形项之间的坐标转换 其他 概述 The Graphics View Coordinate System 图形视图坐标系统是Qt图形视图框架的重要组成部分…...
视频号小店类目资质如何申请?新手看一遍就懂了!
我是电商珠珠 大家在视频号小店后台新增商品的时候,需要先完成类目资质的申请,通过后才可以上架相关商品。 而类目资质分为普通类目和特殊类目,如果你所上架的商品属于开放类目,那么就去按照普通类目资质去申请。 如果是定向准…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...
多元隐函数 偏导公式
我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z、 …...