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

FFmpeg+WebSocket+JsMpeg实时视频流实现方案

之前写的使用FFmpeg + Nginx + HLS流媒体播放方案,适合对实时性要求不高的需求,存在延迟,FFmpeg需要将视频流存储到本地文件,而本次方案FFmpeg不需要将视频流存储到本地文件,而是直接将转换后的视频流(如MJPEG格式)通过标准输出(stdout)传递给WebSocket服务器,WebSocket服务器再将数据实时推送到前端。这种方式是实时流传输,适合需要低延迟的场景。

以下是详细的实现逻辑:


1. FFmpeg 直接输出到 WebSocket 服务器

FFmpeg 通过命令行参数将 RTSP 流转换为 MJPEG 格式,并将输出直接发送到标准输出(stdout),而不是保存到文件。WebSocket 服务器通过 Node.js 的 child_process 模块捕获 FFmpeg 的输出,并将其转发给连接的客户端。

FFmpeg 命令
ffmpeg -i rtsp://your_rtsp_stream_url -f mjpeg -qscale:v 2 -
  • -i rtsp://your_rtsp_stream_url:输入 RTSP 流地址。
  • -f mjpeg:输出格式为 MJPEG。
  • -qscale:v 2:设置视频质量(值越小质量越高)。
  • -:将输出发送到标准输出(stdout),而不是文件。

2. WebSocket 服务器捕获 FFmpeg 输出

WebSocket 服务器通过 Node.js 启动 FFmpeg 进程,并监听其 stdout 数据流。每当 FFmpeg 输出一帧数据时,WebSocket 服务器就将这帧数据发送给所有连接的客户端。

WebSocket 服务器代码 (server.js)
const { spawn } = require('child_process');
const WebSocket = require('ws');// 创建 WebSocket 服务器
const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', (ws) => {console.log('Client connected');// 启动 FFmpeg 进程const ffmpeg = spawn('ffmpeg', ['-rtsp_transport', 'tcp', // 使用 TCP 传输 RTSP 流(如果 UDP 不稳定)'-i', 'rtsp://admin:password@192.168.1.60:554/Streaming/Channels/101/', // RTSP 流地址'-f', 'mpegts', // 输出格式为 MPEG-TS'-codec:v', 'mpeg1video', // 使用 MPEG-1 编码'-s', '640x360', // 分辨率'-b:v', '800k', // 视频比特率'-bf', '0', // 禁用 B 帧'-an', // 禁用音频'pipe:1' // 输出到标准输出]);// 将 FFmpeg 的输出发送到 WebSocket 客户端ffmpeg.stdout.on('data', (data) => {if (ws.readyState === ws.OPEN) {ws.send(data); // 发送二进制数据}});// 处理 FFmpeg 的错误输出ffmpeg.stderr.on('data', (data) => {console.error(`FFmpeg error: ${data}`);});// 处理 FFmpeg 进程退出ffmpeg.on('close', (code) => {console.log(`FFmpeg process exited with code ${code}`);});// 客户端断开连接时关闭 FFmpeg 进程ws.on('close', () => {console.log('Client disconnected');ffmpeg.kill(); // 杀死 FFmpeg 进程});
});console.log('WebSocket server is running on ws://localhost:8080');

3. 前端使用 JsMpeg 播放视频流

前端通过 JsMpeg 库连接到 WebSocket 服务器,并实时解码和播放 MJPEG 视频流。

前端代码 (index.html)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Video Streaming</title><script src="https://cdn.jsdelivr.net/npm/jsmpeg/jsmpeg.min.js"></script>
</head>
<body><canvas id="video-canvas"></canvas><script>// 创建 JsMpeg 播放器const canvas = document.getElementById('video-canvas');const player = new JSMpeg.Player('ws://localhost:8080', {canvas: canvas});</script>
</body>
</html>

4. 运行流程

  1. FFmpeg

    • 从 RTSP 流中读取视频数据。
    • 将视频数据转换为 MJPEG 格式。
    • 将转换后的数据通过标准输出(stdout)发送。
  2. WebSocket 服务器

    • 启动 FFmpeg 进程并捕获其 stdout 数据。
    • 将捕获到的数据通过 WebSocket 发送给前端。
  3. 前端

    • 使用 JsMpeg 连接到 WebSocket 服务器。
    • 接收并解码 MJPEG 数据,实时显示在 <canvas> 中。

5. 优点

  • 实时性:视频流直接从 FFmpeg 推送到前端,延迟较低。
  • 无需存储:视频流不需要保存到本地文件,节省磁盘空间。
  • 简单易用:只需运行 FFmpeg 和 WebSocket 服务器即可。

6. 注意事项

  • FFmpeg 性能:如果 RTSP 流的分辨率较高,FFmpeg 的转换可能会占用较多 CPU 资源。可以通过调整 -qscale:v 参数来优化性能。
  • 网络带宽:MJPEG 格式的视频流数据量较大,确保网络带宽足够。
  • WebSocket 连接数:如果有多个客户端连接,WebSocket 服务器需要处理更多的数据转发,可能会增加服务器负载。

7. 总结

通过这种方式,FFmpeg 直接将 RTSP 流转换为 MJPEG 格式并输出到 WebSocket 服务器,WebSocket 服务器再将数据实时推送到前端,前端使用 JsMpeg 进行播放。整个过程无需存储视频文件,适合实时视频流传输的场景。

相关文章:

FFmpeg+WebSocket+JsMpeg实时视频流实现方案

之前写的使用FFmpeg Nginx HLS流媒体播放方案&#xff0c;适合对实时性要求不高的需求&#xff0c;存在延迟&#xff0c;FFmpeg需要将视频流存储到本地文件&#xff0c;而本次方案FFmpeg不需要将视频流存储到本地文件&#xff0c;而是直接将转换后的视频流&#xff08;如MJPE…...

【Linux】Linux 文件系统—— 探讨软链接(symbolic link)

ℹ️大家好&#xff0c;我是练小杰&#xff0c;周五又到了&#xff0c;明天应该就是牛马的休息日了吧&#xff01;&#xff01;&#x1f606; 前天我们详细介绍了 硬链接的特点&#xff0c;现在继续探讨 软链接的特点&#xff0c;并且后续将添加更多相关知识噢&#xff0c;谢谢…...

排序与算法:插入排序

执行效果 插入排序的执行效果是这样的&#xff1a; 呃……看不懂吗&#xff1f;没关系&#xff0c;接着往下看介绍 算法介绍 插入排序&#xff08;Insertion Sort&#xff09;是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c…...

HashMap 详解

一、核心特性 HashMap集合的key是无序不可重复的。 ①无序&#xff1a;插入顺序和取出顺序不一定相同。 ②不可重复&#xff1a;key具有唯一性。 向HashMap集合中put时&#xff0c;key如果重复的话&#xff0c;value会覆盖。 二、HashMap集合的key具有唯一性&#xff0c;向ke…...

DAY07 Collection、Iterator、泛型、数据结构

学习目标 能够说出集合与数组的区别数组:1.是引用数据类型的一种2.可以存储多个元素3.数组的长度是固定的 int[] arr1 new int[10]; int[] arr2 {1,2,3};4.数组即可以存储基本类型的数据,又可以存储引用数据类型的数据int[],double[],String[],Student[]集合:1.是引用数据类…...

计算机网络之物理层——基于《计算机网络》谢希仁第八版

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff0…...

简讯:Rust 2024 edition and v1.85.0 已发布

详见 https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html 升级方法&#xff1a;rustup update stable...

DeepSeek写俄罗斯方块手机小游戏

DeepSeek写俄罗斯方块手机小游戏 提问 根据提的要求&#xff0c;让DeepSeek整理的需求&#xff0c;进行提问&#xff0c;内容如下&#xff1a; 请生成一个包含以下功能的可运行移动端俄罗斯方块H5文件&#xff1a; 核心功能要求 原生JavaScript实现&#xff0c;适配手机屏幕 …...

uniapp中引入Vant Weapp的保姆级教学(包含错误处理)

废话不多说&#xff0c;直接上方法&#xff0c;网上的教学好多都是错误的 1.安装vant weapp 在Hbuilder的终端&#xff0c;输入以下代码 npm install vant/weapp -S --production 2.新建wxcomponents文件夹 在项目的跟目录新建一个“wxcomponents’文件夹&#xff0c;与app.…...

【Python爬虫(20)】解锁Python爬虫数据存储秘籍:文件存储全攻略

【Python爬虫】专栏简介&#xff1a;本专栏是 Python 爬虫领域的集大成之作&#xff0c;共 100 章节。从 Python 基础语法、爬虫入门知识讲起&#xff0c;深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑&#xff0c;覆盖网页、图片、音频等各类数据爬取&#xff…...

关于Unity的一些基础知识点汇总

1.Prefab实例化后&#xff0c;哪些资源是共用的&#xff1f;哪些资源是拷贝的&#xff1f; 共用资源 脚本组件&#xff1a;实例化后的 Prefab 共享脚本组件的代码。若脚本中无状态数据&#xff0c;多个实例对脚本方法的调用会有相同逻辑。比如一个控制物体移动的脚本&#xff0…...

SpringCould+vue3项目的后台用户管理的CURD【Taurus教育平台】

文章目录 一.SpringCouldvue3项目的后台用户管理的CURD【Taurus教育平台】 1.1 背景 二.用户列表&#xff08;分页查询&#xff09; 2.1 前端Vue3 &#xff08;Vue3-Element-Admin&#xff09;2.2 后端SpringCould 处理 三. 用户信息删除 3.1 前端Vue3 &#xff08;Vue3-Eleme…...

功能说明并准备静态结构

功能说明并准备静态结构 <template><div class"card-container"><!-- 搜索区域 --><div class"search-container"><span class"search-label">车牌号码&#xff1a;</span><el-input clearable placeho…...

solidity之Foundry安装配置(一)

一门面向合约的高级编程语言&#xff0c;主要用来编写以太坊只能合约。 Solidity受C语言&#xff0c;Python和js影响&#xff0c;但为编译成为以太坊虚拟机字节码在EVM上执行&#xff0c;很多特性和限制都和EVM相关。 Solidity 是静态类型语言&#xff0c;支持继承、库、自定义…...

请解释 Vue 中的生命周期钩子,不同阶段触发的钩子函数及其用途是什么?

vue生命周期钩子详解&#xff08;Vue 3版本&#xff09; 一、生命周期阶段划分 Vue组件的生命周期可分为四大阶段&#xff0c;每个阶段对应特定钩子函数&#xff1a; 创建阶段&#xff1a;初始化实例并准备数据挂载阶段&#xff1a;将虚拟DOM渲染为真实DOM更新阶段&#xff…...

C#上位机--选择语句(switch)

在 C# 上位机开发的广阔领域中&#xff0c;流程控制语句如同程序的 “交通枢纽”&#xff0c;精准地引导着程序的执行路径。继深入探讨if语句后&#xff0c;我们将目光聚焦于另一个重要的流程控制语句 ——switch语句。switch语句以其独特的多路分支结构&#xff0c;为处理多条…...

Hadoop初体验

一、HDFS初体验 1. shell命令操作 hadoop fs -mkdir /itcast hadoop fs -put zookeeper.out /itcast hadoop fs -ls / 2. Web UI页面操作 结论&#xff1a; HDFS本质就是一个文件系统有目录树结构 和Linux类似&#xff0c;分文件、文件夹为什么上传一个小文件也这…...

在vue2中操作数组,如何保证其视图的响应式

在 Vue 2 中&#xff0c;操作数组时需要注意一些方法不会触发视图的响应式更新。为了确保数组的操作是响应式的&#xff0c;可以使用 Vue 提供的响应式方法。以下是一些常见的操作及其替代方法&#xff1a; 使用 Vue.set 方法&#xff1a; 当你需要通过索引直接修改数组中的某个…...

CentOS的ssh复制文件

1.前提 首先要已经连接上了对方的ssh 2.命令 scp [文件] 目标IP:目标路径 例如&#xff1a; $PWD是一个环境变量&#xff0c;可以获取当前绝对目录&#xff0c;ssh上传的时候一定要确保对方有这个目录才行&#xff0c;不然会报错 3.递归上传 scp -r 目录 目标IP:路径 可以…...

Spring Cloud — Hystrix 服务隔离、请求缓存及合并

Hystrix 的核心是提供服务容错保护&#xff0c;防止任何单一依赖耗尽整个容器的全部用户线程。使用舱壁隔离模式&#xff0c;对资源或失败单元进行隔离&#xff0c;避免一个服务的失效导致整个系统垮掉&#xff08;雪崩效应&#xff09;。 1 Hystrix监控 Hystrix 提供了对服务…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

Vue 模板语句的数据来源

&#x1f9e9; Vue 模板语句的数据来源&#xff1a;全方位解析 Vue 模板&#xff08;<template> 部分&#xff09;中的表达式、指令绑定&#xff08;如 v-bind, v-on&#xff09;和插值&#xff08;{{ }}&#xff09;都在一个特定的作用域内求值。这个作用域由当前 组件…...