3种ffmpeg-web端视频直播推流方案

ffmpeg-web端视频直播推流方案

记录了三种 ffmpeg 工具进行推流的方法,并在web端实现直播效果。

一. node-media-server + ffmpeg 推流rtmp

安装node-media-server依赖,新建app.js运行

npm install node-media-server -g

const  NodeMediaServer  = require('node-media-server');
const config = {
    rtmp: {
        port: 1935,
        chunk_size: 60000,
        gop_cache: true,
        ping: 60,
        ping_timeout: 30
    },
    http: {
        port: 8000,
        allow_origin: '*'
    }
};
var nms = new NodeMediaServer(config);
nms.run();

node app.js

执行ffmpeg推流

官网下载ffmpeg并配置把bin目录添加到环境变量
ffmpeg -version 查看版本
mpeg -list_devices true -f dshow -i dummy 查看可用以音视频设备

使用本地摄像头推流

ffmpeg -f dshow -i video="Integrated Camera":audio="麦克风阵列 (Synaptics SmartAudio HD)" -vcodec libx264 -acodec copy -preset:v ultrafast -tune:v zerolatency -f flv "rtmp://192.168.20.107:1935/live/home"

使用网络摄像头推流

ffmpeg -threads 5 -i rtsp://admin:px123456@192.168.20.100:554/Streaming/Channels/101 -tune zerolatency -preset ultrafast -vcodec libx264 -threads 5 -b:v 400k -s 720x576 -r 25 -acodec libfaac -b:a 64k -f flv rtmp://192.168.20.107:1935/live/home

rtsp://{账号}:{密码}@{ip}:{端口}/根据摄像头厂牌区分

rtmp://{本地ip}:1935/live/home

本地ip地址要设置为与网络摄像头同一网段

web端HTML页面

因为各浏览器不再支持flash,需要使用flv.js插件
 

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script src="https://cdn.bootcss.com/flv.js/1.4.0/flv.min.js"></script>
<video id="videoElement" style="width: 80%;" controls="controls"></video>
<script>
    if (flvjs.isSupported()) {//检查flvjs能否正常使用
        var videoElement = document.getElementById('videoElement');//使用id选择器找到第二步设置的dom元素
        var flvPlayer = flvjs.createPlayer({//创建一个新的flv播放器对象
            type: 'flv',//类型flv
            url: 'http://192.168.20.107:8000/live/home.flv'//flv文件地址
        },{
            enableWorker: true,
            enableStashBuffer: false,
            stashInitialSize: 128
        });
        flvPlayer.attachMediaElement(videoElement);//将flv视频装载进video元素内
        flvPlayer.load();//载入视频
        flvPlayer.play();//自动播放
    }
</script>
</body>
</html>

【免费分享】音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击788280672加群免费领取~

二. nginx + ffmpeg 推流hls

hls流延迟比较大,按官方的说法60秒内算正常!

下载安装nginx

Windows下安装方法:www.cnblogs.com/qfb620/p/55…

Linux下安装:blog.csdn.net/wenqiangluy…

配置nginx

修改配置文件:/conf/nginx.conf ,在server内添加:
 

location /hls {
	root html;
	#add_header Cache-Control no-cache;
	add_header Access-Control-Allow-Origin *;
}

修改配置文件:/conf/mime.types ,在types内添加:

application/vnd.apple.mpegurl m3u8;
application/x-mpegURL m3u8;
video/mp2t ts;

ffmpeg推流:

要在html目录下创建hls目录
ffmpeg -i "rtsp://admin:px123456@192.168.20.100:554/Streaming/Channels/101" -vcodec libx265 -threads 5 -preset ultrafast -c copy -f hls -hls_time 5.0 -hls_list_size 1 15 D:/tool/Science/nginx-1.18.0/html/hls/test.m3u8

1. -hls_time n: 设置每片的长度,默认值为2。单位为秒
2. -hls_list_size n:设置播放列表保存的最多条目,设置为0会保存有所片信息,默认值为5
3. -hls_wrap n:设置多少片之后开始覆盖,如果设置为0则不会覆盖,默认值为0.这个选项能够避免在磁盘上存储过多的片,而且能够限制写入磁盘的最多的片的数量
4. -hls_start_number n:设置播放列表中sequence number的值为number,默认值为0

web端HTML页面

需要使用video.js插件
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>video.js</title>
    <link href="https://unpkg.com/video.js@6.11.0/dist/video-js.min.css" rel="stylesheet">
    <script src="https://unpkg.com/video.js@6.11.0/dist/video.min.js"></script>
    <script src="https://unpkg.com/videojs-flash/dist/videojs-flash.js"></script>
    <script src="https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js"></script>
  </head>
  <body>
    <video id="my-player" class="video-js" controls>
        <source src="http://localhost/hls/test.m3u8" type="application/x-mpegURL">
        <p class="vjs-no-js">
          not support
        </p>
    </video>
    <script type="text/javascript">
      var player = videojs('my-player',{
        width:400,
        heigh:200
      });
    </script>
  </body>

三. 通过webSocket发送MPEG,前端解析MPEG绘制canvas

这是我试过延迟最小的方法,0.5秒左右,但是非常耗cpu。

创建app.js,安装WebSocket等相应模块

var fs = require('fs'), http = require('http'), WebSocket = require('ws');

// console.log(process.argv)
if (process.argv.length < 3) {
	// console.log('输入正确参数');
	  process.argv[2]='supersecret';
    process.argv[3]='8081';
    process.argv[4]='8082';
// 	process.exit();
}

var stream_secret = process.argv[2];//密码
var stream_port = process.argv[3] || 8081;//ffpeng推送端口
var websocket_port = process.argv[4] || 8082;//前端websocket端口 ,比如:8082
var record_stream = false;
var totalSize = 0;

function initWebSocket(websocket_port) {
	var clientMap = new Map();//缓存,实现多个视频流同时播放的问题
	
	var socketServer = new WebSocket.Server({
		port : websocket_port,
		perMessageDeflate : false
	});
	socketServer.on('connection', function(socket, upgradeReq) {
		var url = upgradeReq.socket.remoteAddress + upgradeReq.url;
		var key = url.substr(1).split('/')[1];//key就是通过url传递过来的标识比如:(ws://127.0.0.1:8082/live3)其中live3就是这个标识,其他的流可随机生成其他的字符串
		var clients = clientMap.get(key);
		if(!clients){
			clients = new Set();
			clientMap.set(key,clients);
		}
		clients.add(socket);
		totalSize++;
		process.stdout.write("[INFO]:a new connection, the current number of connections: " + totalSize + ".\r");
		socket.on('close', function(code, message) {
			var clientSet = clientMap.get(key);
			if(clientSet){
				clientSet.delete(socket);
				totalSize--;
				if(clientSet.size == 0){
					clientMap.delete(key);
				}
			}
			process.stdout.write("[INFO]:close a connection, the current number of connections:" + totalSize + ".\r");
		});
	});

	socketServer.broadcast = function(data, theme) {
		var clients = clientMap.get(theme);
		if (clients) {
			clients.forEach(function (client, set) {
				if(client.readyState === WebSocket.OPEN){
					client.send(data);
				}
			});
		}
	};
	return socketServer;
}

function initHttp(stream_port, stream_secret, record_stream, socketServer) {
	var streamServer = http.createServer(
			function(request, response) {
				var params = request.url.substr(1).split('/');
				if (params.length != 2) {
					process.stdout.write("\n[ERROR]:Incorrect parameters, enter password and push theme");
					response.end();
				}
				if (params[0] !== stream_secret) {
					process.stdout.write("\n[ERROR]:Password error: "+request.socket.remoteAddress+":"+request.socket.remotePort+"");
					response.end();
				}
				response.connection.setTimeout(0);
				request.on('data', function(data) {
					socketServer.broadcast(data, params[1]);
					if (request.socket.recording) {
						request.socket.recording.write(data);
					}
				});
				request.on('end', function() {
					process.stdout.write("\n[INFO]:close request");
					if (request.socket.recording) {
						request.socket.recording.close();
					}
				});
				if (record_stream) {
					var path = 'recordings/' + Date.now() + '.ts';
					request.socket.recording = fs.createWriteStream(path);
				}
			}).listen(stream_port);
			console.log('started rtsp WebSocket service in secret is [%s], service port is [%s], ws port is [%s].',stream_secret,stream_port,websocket_port);
}

initHttp(stream_port, stream_secret, record_stream,
		initWebSocket(websocket_port));

执行ffmpeg(封装run.js)

我把ffmpeg命令封装成js文件,以方便执行多条命令。
require('shelljs/global');

var version = exec('node --version', {silent:true}).output;

exec(`ffmpeg -i "rtsp://admin:px123456@192.168.3.21:554/Streaming/Channels/101" -q 0 -f mpegts -codec:v mpeg1video -s 1680x945 http://127.0.0.1:8081/supersecret/live1`, function(status, output) {
  console.log('Exit status:', status);
  console.log('Program output:', output);
});
exec(`ffmpeg -i "rtsp://admin:px123456@192.168.3.21:554/Streaming/Channels/101" -q 0 -f mpegts -codec:v mpeg1video -s 1680x945 http://127.0.0.1:8081/supersecret/live2`, function(status, output) {
  console.log('Exit status:', status);
  console.log('Program output:', output);
});
exec(`ffmpeg -i "rtsp://admin:px123456@192.168.3.21:554/Streaming/Channels/101" -q 0 -f mpegts -codec:v mpeg1video -s 1680x945 http://127.0.0.1:8081/supersecret/live3`, function(status, output) {
  console.log('Exit status:', status);
  console.log('Program output:', output);
});
exec(`ffmpeg -i "rtsp://admin:px123456@192.168.3.21:554/Streaming/Channels/101" -q 0 -f mpegts -codec:v mpeg1video -s 1680x945 http://127.0.0.1:8081/supersecret/live4`, function(status, output) {
  console.log('Exit status:', status);
  console.log('Program output:', output);
});

创建index.html

需要使用 jsmpeg.js插件
页面要运行到服务器中!
<!DOCTYPE html>
<html>
<head>
	<title></title>
	<style type="text/css">
		html, body {
			text-align: center;
		}
	</style>
	
</head>
<body>
	<canvas id="video-canvas"></canvas>
	<canvas id="video-canvas1"></canvas>
	<canvas id="video-canvas2"></canvas>
	<canvas id="video-canvas3"></canvas>
	
	<script type="text/javascript" src="jsmpeg.min.js"></script>
	<script type="text/javascript">
		var canvas = document.getElementById('video-canvas');
		var url = 'ws://ip:8082/live1';
		var player = new JSMpeg.Player(url, {
		    canvas: canvas,
		});
		console.log(player)
		
		var canvas1 = document.getElementById('video-canvas1');
		var url1 = 'ws://ip:8082/live2';
		var player1 = new JSMpeg.Player(url1, {canvas: canvas1});

		var canvas2 = document.getElementById('video-canvas2');
		var url2 = 'ws://ip:8082/live3';
		var player2 = new JSMpeg.Player(url2, {canvas: canvas2});

		var canvas3 = document.getElementById('video-canvas3');
		var url3 = 'ws://ip:8082/live4';
		var player3 = new JSMpeg.Player(url3, {canvas: canvas3});
		
	</script>
</body>
</html>

原文链接 3种ffmpeg-web端视频直播推流方案 - 掘金

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

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

相关文章

flash-attn库安装记录

flash-attn库安装记录 第一步&#xff1a; 安装好cuda11.7 第二步&#xff1a; 使用代码export CUDA_HOME/usr/local/cuda-11.7让库找到cuda路径 第三步&#xff1a; 使用pip install flash-attn --no-build-isolation安装 安装成功显示

【REMB 】翻译:草案remb-03

REMB REMB消息 以及 绝对时间戳选项 在带宽估计中的使用 :an absolute-value timestamp option for use in bandwidth estimatoin. 接收方带宽估计的RTCP消息 REMB 这位大神翻译的更好。 RTCP message for Receiver Estimated Maximum Bitrate draft-alvestrand-rmcat-remb-03…

图像处理------亮度

from PIL import Imagedef change_brightness(img: Image, level: float) -> Image:"""按照给定的亮度等级&#xff0c;改变图片的亮度"""def brightness(c: int) -> float:return 128 level (c - 128)if not -255.0 < level < 25…

web:ezbypass-cat(白名单目录穿透漏洞、重定向)

题目 进入页面&#xff0c;页面显示如下 随便输入 显示密码错误 查看源代码&#xff0c;没有发现提示 尝试一下sql注入&#xff0c;也没有结果&#xff0c;这里看了大佬的wp&#xff0c;发现是目录穿透 使用bp抓包&#xff0c;网站目录爆破&#xff0c;发现flag.html&#xf…

【51单片机系列】proteus仿真单片机的串口通信

本文参考&#xff1a;https://zhuanlan.zhihu.com/p/425809292。 在proteus之外使用串口软件和单片机通信。通过在proteus设计一个单片机接收PC发送的数据&#xff0c;并将接收的数据发送出去&#xff0c;利用软件【Configure Virtual Serial Port Driver】创建一对虚拟串口&am…

Spring高手之路-Spring事务失效的场景详解

目录 前言 Transactional 应用在非 public 修饰的方法上 同一个类中方法调用&#xff0c;导致Transactional失效 final、static方法 Transactional的用法不对 Transactional 注解属性 propagation 设置不当 Transactional注解属性 rollbackFor 设置错误 用错注解 异常…

rust跟我学:模块编写与使用

图为RUST吉祥物 大家好,我是get_local_info作者带剑书生,这里用一篇文章讲解get_local_info中模块的使用。 首先,先要了解get_local_info是什么? get_local_info是一个获取linux系统信息的rust三方库,并提供一些常用功能,目前版本0.2.4。详细介绍地址:[我的Rust库更新]g…

考研C语言刷题篇之分支循环结构一

目录 第一题 第二题 方法一&#xff1a;要循环两次&#xff0c;一次求阶乘&#xff0c;一次求和。 注意&#xff1a;在求和时&#xff0c;如果不将sum每次求和的初始值置为1&#xff0c;那么求和就会重复。 方法二&#xff1a; 第三题 方法一&#xff1a;用数组遍历的思想…

认识并使用JWT

认识并使用JWT 一、互联网世界的用户认证二、对JWT的基本认知三、JWT的原理1 Header2 Payload3 Signature4 [参考资料](https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html) 四、使用JWT1、引入依赖2、jwt的生成与解析3、测试3.1 生成jwt3.2 解析jwt 一、互…

探索单元测试和 E2E 测试:提升软件质量的关键步骤(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

驾驭车联网的力量:深入车联网网络架构

车联网&#xff0c;作为移动互联网之后的新风口&#xff0c;以网联思想重新定义汽车&#xff0c;将其从简单的出行工具演化为个人的第二空间。车联网涵盖智能座舱和自动驾驶两大方向&#xff0c;构建在网联基础上&#xff0c;犀思云多年深度赋能汽车行业&#xff0c;本文将从车…

iphone 5s的充电时序原理图纸,iPAD充电讲解

上一篇写了iphone 5的时序。那是电池供电的开机时序。iphone 5s也是差不多的过程&#xff0c;不说了。现在看iphone5s手机充电时候的时序。iphone5s充电比iphone5充电简单了很多。 首先是usb接口接到手机上&#xff0c;usb线连接到J7接口上。J7接口不只是接usb&#xff0c;还能…

Express安装与基础使用

一、express 介绍 express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架&#xff0c; 官方网站&#xff1a; Express - 基于 Node.js 平台的 web 应用开发框架 - Express中文文档 | Express中文网 中文文档&#xff1a; 路由 - Express 中文文档 简单来说&am…

二次开发在线预约上门服务、预约到家系统 增加开发票功能 轮播图链接跳转 uniapp代码

客户具体要求&#xff1a; 1、在我的个人中心里面增加一个 开票功能&#xff0c;点击进去之后可以查看到能开票的订单列表&#xff0c;如果是个人是填写姓名电话邮箱&#xff0c;就是填写单位名称 税号 邮箱&#xff0c;提交申请到后台审核&#xff0c;如果审核通过后线下人工…

预处理/预编译详解(C/C++)

在上一篇的bolg中的编译与链接中提到过预处理&#xff0c;但只是较为简单的讲解&#xff0c;本篇将会对预处理进行详细的讲解。 其中在预处理中很重要的一个一个知识点是#define定义常量与宏&#xff0c;还区分了宏与函数的区别&#xff0c;以及#和##符号&#xff0c;还涉及条件…

ADA-YOLO:YOLOv8+注意力+Adaptive Head,mAP提升3%

生物医学图像分析中的目标检测和定位至关重要&#xff0c;尤其是在血液学领域&#xff0c;检测和识别血细胞对于诊断和治疗决策至关重要。虽然基于注意力的方法在各个领域中目标检测方面取得了显著的进展&#xff0c;但由于医学影像数据集的独特挑战&#xff0c;其在医学目标检…

【用队列实现栈】【用栈实现队列】Leetcode 232 225

【用队列实现栈】【用栈实现队列】Leetcode 232 225 队列的相关操作栈的相关操作用队列实现栈用栈实现队列 ---------------&#x1f388;&#x1f388;题目链接 用队列实现栈&#x1f388;&#x1f388;------------------- ---------------&#x1f388;&#x1f388;题目链…

vue2使用qiankun微前端(跟着步骤走可实现)

需求&#xff1a;做一个vue2的微前端&#xff0c;以vue2为主应用&#xff0c;其他技术栈为子应用&#xff0c;比如vue3&#xff0c;本文章只是做vue2一套的微前端应用实现&#xff0c;之后解决的一些问题。vue3子应用可以看我另一篇vue3vitets实现qiankun微前端子应用-CSDN博客…

IDEA 2022.3.3 安装教程

1.下载2022.3.3版本IDEA 链接&#xff1a;https://pan.baidu.com/s/1z-Yfl7fWHgqz8SQLn2-u0g?pwd949u 提取码&#xff1a;949u 2.安装 下载完成后&#xff0c;双击exe安装包&#xff0c; 点击next 3.选择方式3 4.将下面文件复制到任意位置&#xff08;不要有中文路径&…

❤ Uniapp使用二 ( 日常使用篇)

❤ Uniapp使用二 ( 日常使用篇) 一、表单 1、基础表单验证 form <form submit"formSubmit" reset"formReset"> <view class"uni-form-item uni-column"><view class"title">请选择类型{{selectvalue}}</view&…
最新文章