RTSP前端实时流

因项目需求探索前端实时流,本文介绍了 RTSP 前端不能直接播放,需中间层转换协议,如 RTSP 转 RTMP、HLS、HTTP-FLV,分别阐述其特点、配置和播放方式,还提及关键帧、延迟与卡顿的关系,以及直播平台使用云服务商 CDN 的流程。

概览

视频有一个流的概念,所以称流媒体。实时视频的流很好理解,因为视频是实时的,需要有一个地方不停地输出视频出来,所以整个视频可以用流来称呼。那么视频可否直接输出到前端页面上呢?可惜,如果可以的话,就没有我这篇文章了。现在摄像头的实时视频流普遍采用的是 RTSP 协议,而前端并不能直接播放 RTSP 的视频流。

  • RTSP(Real-Time Stream Protocol),是 TCP/UDP 协议体系中的一个应用层协议,跟 HTTP 处在同一层。RTSP 在体系结构上位于 RTP 和RTCP 之上,它使用 TCP 或者 RTP 完成数据传输。RTSP 实时效果非常好,适合视频聊天、视频监控等方向。


那么我们就需要一层中间层,来将 RTSP 流转成前端可以支持的协议,这也引申出了目前实时流技术的几种方向:

  • RTSP -> RTMP
  • RTSP -> HLS
  • RTSP -> RTMP -> HTTP-FLV

 

RTMP

RTMP(Real Time Messaging Protocol)是属于 Adobe 的一套视频协议,这套方案需要专门的 RTMP 流媒体,并且如果想要在浏览器上播放,无法使用 HTML5 的 video 标签,只能使用 Flash 播放器。(通过使用 video.js@5.x 以下的版本可以做到用 video 标签进行播放,但仍然需要加载 Flash)。它的实时性在几种方案中是最好的,但是由于只能使用 Flash 的方案,所以在移动端就直接 GG 了,在 PC 端也是明日黄花。
由于下面的两种方法也需要用到 RTMP,所以这里就展示一下 RTSP 流如何转换成 RTMP ,我们使用 ffmpeg+Nginx+nginx-rtmp-module 来做这件事:

 

# 在 http 同一层配置 rtmp 协议的相关字段
rtmp {
    server {
    	  # 端口
        listen 1935;
    		# 路径
        application test {
    		# 开启实时流模式
            live on;
            record off;
        }
    }
}
# bash 上执行 ffmpeg 把 rtsp 转成 rtmp,并推到 1935 这个端口上
ffmpeg -i "rtsp://xxx.xxx.xxx:xxx/1" -vcodec copy -acodec copy -f flv "rtmp://127.0.0.1:1935/live/"

这样我们就得到了一个 RTMP 的流,我们可以直接用 VLC 或者 IINA 来播放这个流。

HLS 

HLS(HTTP Live Streaming)是苹果公司提出的基于 HTTP 协议的的流媒体网络传输协议,它的工作原理是把整个流分成一个个小的基于 HTTP 的文件来下载,每次只下载一些。HLS 具有跨平台性,支持 iOS/Android/浏览器,通用性强。但是它的实时性差:苹果官方建议是请求到3个片之后才开始播放。所以一般很少用 HLS 做为互联网直播的传输协议。假设列表里面的包含5个 ts 文件,每个 TS 文件包含5秒的视频内容,那么整体的延迟就是25秒。苹果官方推荐的小文件时长是 10s,所以这样就会有30s(n x 10)的延迟。
下面是 HLS 实时流的整个链路:

从图中可以看出来我们需要一个服务端作为编码器和流分割器,接受流并不断输出成流片段(stream),然后前端再通过一个索引文件,去访问这些流片段。那么我们同样可以使用 nginx+ffmpeg 来做这件事情。

# 在 rtmp 的 server 下开启 hls
# 作为上图中的 Server,负责流的处理
application hls{
		live on;
		hls on;
 		hls_path xxx/; #保存 hls 文件的文件夹
		hls_fragment 10s;
}
# 在 http 的 server 中添加 HLS 的配置:
# 作为上图中的 Distribution,负责分片文件和索引文件的输出
location /hls {
  	# 提供 HLS 片段,声明类型
  	types {
    	application/vnd.apple.mpegurl m3u8;
    	video/mp2t ts;
  	}
  	root /Users/mark/Desktop/hls; #访问切片文件保存的文件夹
  	# Cache-Controll no-cache;
  	expires -1;
}

然后同样使用 ffmpeg 推流到 hls 路径上:

ffmpeg -i "rtsp://xxx.xxx.xxx:xxx/1" -vcodec copy -acodec copy -f flv rtmp://127.0.0.1:1935/hls

这个时候可以看到文件夹里已经有许多流文件存在,且不停地更新:

然后我们可以使用 video.js+video.js-contrib-hls 来播放这个视频:

<html>
<head>
<title>video</title>
<!-- 引入css -->
<link href="https://unpkg.com/video.js/dist/video-js.min.css" rel="stylesheet">


</head>
<body>
<div class="videoBox">
    <video id="video" class="video-js vjs-default-skin" controls>
        <source src="http://localhost:8080/hls/test.m3u8" type="application/x-mpegURL"> 
    </video>
</div>

</body>
</html>
<script src="https://unpkg.com/video.js/dist/video.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.15.0/videojs-contrib-hls.min.js"></script>
<script>
videojs.options.flash.swf = "./videojs/video-js.swf"
		videojs('video', {"autoplay":true}).play();
</script>

在我的测试下,HLS 的延迟在10-20秒左右,我们可以通过调整切片的大小来减少延迟,但是由于架构的限制,延迟是一个不可忽视的问题。

HTTP-FLV

接下来就是重头戏 HTTP-FLV 了,它集合了 HLS 的通用性和 RTMP 的实时性,可以做到在浏览器上用 HTML5 的 video 标签,以较低的延时播放实时流。HTTP-FLV 依靠 MIME 的特性,根据协议中的 Content-Type 来选择相应的程序去处理相应的内容,使得流媒体可以通过 HTTP 传输。除此之外,它可以通过 HTTP 302 跳转灵活调度/负载均衡,支持使用 HTTPS 加密传输,也能够兼容支持 Android,iOS 等移动端。HTTP-FLV 本质上是将流转成 HTTP 协议下的 flv 文件,在 Nginx 上我们可以使用 nginx-http-flv-module 来将 RTMP 流转成 HTTP 流。

其实 flv 格式依然是 Adobe 家的格式,原生 Video 标签无法直接播放,但是好在我们有 bilibili 家的 flv.js,它可以将 FLV 文件流转码复用成 ISO BMFF(MP4 碎片)片段,然后通过 Media Source Extensions 将 MP4 片段喂进浏览器。

在支持浏览器的协议里,延迟排序是这样的:RTMP = HTTP-FLV = WebSocket-FLV < HLS
而性能排序是这样的:RTMP > HTTP-FLV = WebSocket-FLV > HLS

说了这么多,不如直接上手看看吧:

1.首先我们需要一个新的 nginx 插件:nginx-http-flv-module

2.在 nginx.conf 中进行一些新的配置:

# rtmp server
application myvideo {
  	live on;
  	gop_cache: on; #减少首屏等待时间
}

# http server
location /live {
  	flv_live on;
}

3.依然用 ffmpeg 来推流,使用上面 RTMP 的命令 

4.前端 import flv.js,然后使用它来播放

// 前端使用 flv.js,开启实时模式,然后访问这个 nginx 地址下的路径即可
import flvJs from 'flv.js';

export function playVideo(elementId, src) {
  const videoElement = document.getElementById(elementId);
  const flvPlayer = flvJs.createPlayer({
    isLive: true,
    type: 'flv',
    url: src,
  });
  flvPlayer.attachMediaElement(videoElement);
  flvPlayer.load();
}

playVideo('#video', 'http://localhost:8080/live?port=1985&app=myvideo&stream=streamname')

可以看到 flv.js 使用了 video/x-flv 这个 MIME 返回数据。

 

 

如果对延迟有更高的要求,可以尝试下面的操作:

  1. 可以配置 flv.js 的 enableStashBuffer 字段,它是 flv.js 用于控制缓存 buffer 的开关,关闭了之后可以做到最小延迟,但由于没有缓存,可能会看到网络抖动带来的视频卡顿。
  2. 可以尝试关闭 nginx 的 http 配置里的 gop_cache 。gop_cache 又称关键帧缓存,其意义是控制视频的关键帧之间的缓存是否开启。

这里引入了一个关键帧的概念:我们使用最广泛的 H.264 视频压缩格式,它采用了诸如帧内预测压缩/帧间预测压缩等压缩方案,最后得到了 BPI 三种帧:

  • I 帧:关键帧,采用帧内压缩技术。
  • P 帧:向前参考帧,在压缩时,只参考前面已经处理的帧,表示的是当前帧画面与前一帧(前一帧可能是 I 帧也可能是 P 帧)的差别。采用帧间压缩技术。
  • B 帧:双向参考帧,在压缩时,它即参考前面的帧,又参考它后面的帧。B 帧记录的是本帧与前后帧的差别。采用帧间压缩技术。

带有 I 帧、B 帧和 P 帧的典型视频序列。P 帧只需要参考前面的 I 帧或 P 帧,而 B 帧则需要同时参考前面和后面的 I 帧或 P 帧。由于 P/B 帧对于 I 帧都有直接或者间接的依赖关系,所以播放器要解码一个视频帧序列,并进行播放,必须首先解码出 I 帧。假设 GOP(就是视频流中两个I帧的时间距离) 是 10 秒,也就是每隔 10 秒才有关键帧,如果用户在第 5 秒时开始播放,就无法拿到当前的关键帧了。这个时候 gop_cache 就起作用了:**gop_cache 可以控制是否缓存最近的一个关键帧。**开启 gop_cache 可以让客户端开始播放时,立即收到一个关键帧,显示出画面,当然,由于增加了对上一个帧的缓存,所以延时自然就变大了。如果对延时有更高的要求,而对于首屏时间/播放流畅度的要求没那么高的话,那么可以尝试关闭 gop_cache,来达到低延时的效果。

思考

 

延迟与卡顿

实时视频的延时与卡顿是视频质量中最重要的两项指标。 然而,这两项指标从理论上来说,是一对矛盾的关系——需要更低的延时,则表明服务器端和播放端的缓冲区都必须更短,来自网络的异常抖动容易引起卡顿;业务可以接受较高的延时时,服务端和播放端都可以有较长的缓冲区,以应对来自网络的抖动,提供更流畅的体验。

直播厂商是怎么做的?

现在各个直播平台基本上都放弃了以上这些比较传统的方式,使用了云服务商提供的 CDN,但还是离不开前文所说的几种协议与方式。如下图是阿里云的直播服务图。可以看到其流程大概分为这几步:

  1. 视频流推送(主播端使用 RTMP 进行推流)
  2. SDK 推流到 CDN 节点(上传流)
  3. CDN 节点转到直播中心,直播中心具有强大的计算能力,可以提供额外服务诸如落存(录制/录制到云存储/点播),转码,审核,多种协议的输出等。
  4. 直播中间分发到 CDN 节点
  5. 用户播放(阿里云支持 RTMP、FLV 及 HLS 三种播流协议)

​​​​​​​

 

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

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

相关文章

植物大战僵尸杂交版v2.6.1最新版本(附下载链接)

B站游戏作者潜艇伟伟迷于11月3日更新了植物大战僵尸杂交版2.6.1版本&#xff01;&#xff01;&#xff01;&#xff0c;有b站账户的记得要给作者三连关注一下呀&#xff01; 不多废话下载链接放上&#xff1a; 夸克网盘链接&#xff1a;https://pan.quark.cn/s/279e7ed9f878 新…

qsqlmysql.lib的编译和使用

文章目录 打开源码 打开源码 打开qt源码安装路径 src相对路径下的文件Src\qtbase\src\plugins\sqldrivers\mysql 比如我是5.9.9版本我的路径就是&#xff1a;D:\Qt5.9.9\5.9.9\Src\qtbase\src\plugins\sqldrivers\mysql 可以看到待编译的mysql驱动文件 使用IDE打开pro文件进…

Window下PHP安装最新sg11(php5.3-php8.3)

链接: https://pan.baidu.com/s/10yyqTJdwH_oQJnQtWcwIeA 提取码: qz8y 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 (链接失效联系L88467872) 1.下载后解压文件&#xff0c;将对应版本的ixed.xx.win文件放进php对应的ext目录下&#xff0c;如图所示 2.修改ph…

30.超市管理系统(基于springboot和Vue的Java项目)

目录 1.系统的受众说明 2.相关技术和开发环境 2.1 相关技术 2.1.1 Java语言 2.1.2 HTML、CSS、JavaScript 2.1.3 MySQL 2.1.4 Vue.js 2.1.5 SpringBoot 2.2 开发环境 3. 系统分析 3.1 可行性分析 3.1.1 经济可行性 3.1.2 技术可行性 3.1.3 运行可行性 3.2…

去地面算法——depth_clustering算法调试(1)

1 源码下载 论文&#xff1a; 《2016-Fast Range Image-Based Segmentation of Sparse 3D Laser Scans for Online Operation》 《2017-Efficient Online Segmentation for Sparse 3D Laser Scans》 代码&#xff1a;git链接 2 问题记录 2.1 无法找到qt问题 问题截图&…

pyspark入门基础详细讲解

1.前言介绍 学习目标&#xff1a;了解什么是Speak、PySpark&#xff0c;了解为什么学习PySpark&#xff0c;了解课程是如何和大数据开发方向进行衔接 使用pyspark库所写出来的代码&#xff0c;既可以在电脑上简单运行&#xff0c;进行数据分析处理&#xff0c;又可以把代码无缝…

Qt 编写插件plugin,支持接口定义信号

https://blog.csdn.net/u014213012/article/details/122434193?spm1001.2014.3001.5506 本教程基于该链接的内容进行升级&#xff0c;在编写插件的基础上&#xff0c;支持接口类定义信号。 环境&#xff1a;Qt5.12.12 MSVC2017 一、创建项目 新建一个子项目便于程序管理【…

【python】python使用虚拟环境

使用虚拟环境的好处是创建一个独立干净的环境 首先cd到新项目的目录下 创建虚拟环境 使用日期命名方便自己找到版本 python -m venv venv20241114激活虚拟环境 .\venv20241114\Scripts\activate会创建一个文件夹 点进去可以看到是python的脚本所存文件结构 纯净环境 p…

CSS 技巧:如何让 div 完美填充 td 高度

引言 一天哈比比突然冒出一个毫无理头的一个问题: 本文就该问题进行展开… 原文链接: 昆仑虚F2E 一、需求说明 大致需求如下, 当然这里做了些简化 有如下初始代码: 一个自适应的表格每个单元格的宽度固定 200px每个单元格高度则是自适应每个单元格内是一个 div 标签, div 标签…

跟上AI的浪潮

现在AI技术已广泛应用至语音助手、写作、绘图、视频&#xff0c;甚至是各种语言的代码编写。平常我们都是应用别人开发好的模型&#xff0c;或者说智能体&#xff0c;那么我们自己能否做那个开发AI智能体的人&#xff0c;近期加了一个AI学习的大社区&#xff0c;几万在AI道路上…

专题十八_动态规划_斐波那契数列模型_路径问题_算法专题详细总结

目录 动态规划 动态规范五步走&#xff1a; 1. 第 N 个泰波那契数&#xff08;easy&#xff09; 解析&#xff1a; 1.状态表达式&#xff1a; 2.状态转移方程&#xff1a; 3.初始化&#xff1a; 4.填表顺序&#xff1a; 5.返回值 编写代码&#xff1a; 总结&#xff…

MySQL技巧之跨服务器数据查询:基础篇-更新语句如何写

MySQL技巧之跨服务器数据查询&#xff1a;基础篇-更新语句如何写 上一篇已经描述&#xff1a;借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的连接名: MY_ODBC_MYSQL 以及用同样的…

C/C++语言 多项式加法和乘法

多项式加法和乘法 多项式的加法题目描述输入输出样例步骤代码段全局变量设定新建结点合并链表 完整代码 多项式乘法题目描述输入输出样例代码段计算两多项式结果输入 完整代码 多项式的加法 题目描述 输入输出 样例 步骤 总体思想是用链表来做 ① 我们发现输入样例中&#xf…

ArkTs面向对象编程

ArkTs面向对象编程 1.1 面向对象编程概述 1.1.1 什么是面向对象编程 面向对象编程是一种编程范式&#xff0c;它使用“对象”来设计软件和创建可重用的程序设计 对象是包含数据和方法的实体&#xff0c;可以与其他对象进行交互 面相对象编程鼓励使用已有的对象来组合或修改以…

乳腺癌诊断分析——基于聚类分析实现

一、研究背景 乳腺癌属于恶性肿瘤&#xff0c;在早期发现后需要及早将病变组织切除&#xff0c;而且术后还要化疗和放射等辅助治疗&#xff0c;能够抑制癌细胞的扩散和增长。 二、研究目的 研究乳腺癌病人的患病特征通过聚类分析方法对特征进行分类通过上述聚类结果对乳腺诊…

丹摩征文活动|FLUX.1 和 ComfyUI:从部署到上手,轻松驾驭!

FLUX.1 和 ComfyUI&#xff1a;从部署到上手&#xff0c;轻松驾驭&#xff01; FLUX.1历史曲线 黑森林实验室推出了一款名为FLUX.1的先进图像生成模型&#xff0c;根据不同用户需求&#xff0c;提供了三种独特的版本。 FLUX.1-pro&#xff1a;作为专为企业打造的强大闭源版本…

数据分析:16s差异分析DESeq2 | Corncob | MaAsLin2 | ALDEx2

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍DESeq2原理计算步骤结果Corncob原理计算步骤结果MaAsLin2原理计算步骤结果ALDEx2原理计算步骤结果加载R包数据链接数据预处理微生物数据样本信息提取物种名称过滤零值保留结果读取…

OCR识别铁路电子客票

随着中国铁路客运领域进入全面数字化时代&#xff0c;国家税务总局、财政部和国铁集团于2024年10月18日联合发布公告&#xff0c;自2024年11月1日起&#xff0c;推广使用“电子发票&#xff08;铁路电子客票&#xff09;”。这一举措不仅为旅客出行提供了极大的便利&#xff0c…

【MySQL基础刷题】总结题型(三)

十题左右&#xff0c;便于复习 1.查询结果的质量和占比2.每月交易I3.销售分析III4.只出现一次的最大数字5.买下所有产品的客户6.员工的直属部门7.指定日期的产品价格 1.查询结果的质量和占比 avg大神啊… SELECT query_name, ROUND(avg(rating / position), 2) as quality, …

python 同时控制多部手机

在这个智能时代,我们的手机早已成为生活和工作中不可或缺的工具。无论是管理多个社交媒体账号,还是处理多台设备上的事务,如何更高效地控制多个手机成为了每个人的痛点。 今天带来的这个的软件为你提供了一键控制多部手机的强大功能。无论是办公、娱乐,还是社交,你都能通过…