当前位置: 首页 > news >正文

深入理解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,最多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流媒体模块[中]

相关文章:

深入理解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 框架&#xff0c;运行速度非常快&#xff0c;擅长 Api 接口的高并发&#xff0c;如果项目的规模不大&#xff0c;业务相对简单&#xff0c;这个时候我们也推荐您使用 Gin&#xff0c;特别适合微服务框架。 简单路由配置 package mai…...

vue3+threejs新手从零开发卡牌游戏(二十一):添加战斗与生命值关联逻辑

首先将双方玩家的HP存入store中&#xff0c;stores/common.ts代码如下&#xff1a; import { ref, computed } from vue import { defineStore } from piniaexport const useCommonStore defineStore(common, () > {const _font ref() // 字体const p1HP ref(4000) // 己…...

Linux内核err.h文件分析

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

Qt 富文本处理 (字体颜色大小加粗等)

Qt中支持HTML的控件有textEdit 、label 、textBrowser 。 接口&#xff1a;setHtml("Qt"); toHtml(). 文本样式设置 : 可分字设置 &#xff0c;主要使用QTextCharFormat类进行文本样式设置。 示例&#xff1a; QTextCharFormat fmt; //粗体 fmt.setFontWeight…...

消息队列的七种经典应用场景

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

uniapp 微信小程序 canvas 手写板文字重复倾斜水印

核心逻辑 先将坐标系中心点通过ctx.translate(canvasw / 2, canvash / 2) 平移到canvas 中心&#xff0c;再旋转设置水印 假如不 translate 直接旋转&#xff0c;则此时的旋转中心为左上角原点&#xff0c;此时旋转示意如图所示 当translate到中心点之后再旋转&#xff0c;此…...

JavaScript如何制作轮播图

在JavaScript中实现轮播图可以通过多种方式&#xff0c;但最常见的方式是使用数组来存储图片&#xff0c;然后使用setInterval函数定期更改显示的图片。下面是一个简单的例子&#xff1a; 首先&#xff0c;你需要在HTML中设置一些用于显示图片的<img>标签&#xff0c;以…...

【面试经典150 | 动态规划】零钱兑换

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

什么是防火墙,部署防火墙有什么好处?

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

学习鸿蒙基础(10)

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

阿里云对象存储OSS入门

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

[幻灯片]软件需求设计方法学全程实例剖析-03-业务用例图和业务序列图

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 pdf已上传至本号的CSDN资源&#xff0c;或到以下地址下载&#xff1a; http://umlchina.com/training/umlchina_03_bm.pdf...

ctfshow-web入门-xxe

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

Docker数据卷挂载

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

QT_day4:对话框

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

矢量数据库:连接人工智能应用程序的数据复杂性与可用性的桥梁

关注我的公众号&#xff1a;Halo咯咯 简介 矢量数据库是一种专门设计的数据库&#xff0c;专注于高效地存储、管理和操作矢量数据。与传统数据库处理标量值&#xff08;如数字、字符串、日期&#xff09;不同&#xff0c;矢量数据库针对的是那些表现为多维数据点的向量&#xf…...

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 原因&#xff1a;docker.sock不能创建 解决方式&#xff1a; rm -rf /var/run/docker.sock 然后重新启动docker Docker是一种相对使用较简单的容器&#xff0c;我们可以通过以下几种方式获取信息&…...

Qt 图形视图 /图形视图框架坐标系统的设计理念和使用方法

文章目录 概述Qt 坐标系统图形视图的渲染过程Item图形项坐标系Scene场景坐标系View视图坐标系map坐标映射场景坐标转项坐标视图坐标转图形项坐标图形项之间的坐标转换 其他 概述 The Graphics View Coordinate System 图形视图坐标系统是Qt图形视图框架的重要组成部分&#xf…...

视频号小店类目资质如何申请?新手看一遍就懂了!

我是电商珠珠 大家在视频号小店后台新增商品的时候&#xff0c;需要先完成类目资质的申请&#xff0c;通过后才可以上架相关商品。 而类目资质分为普通类目和特殊类目&#xff0c;如果你所上架的商品属于开放类目&#xff0c;那么就去按照普通类目资质去申请。 如果是定向准…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...