记录了三种 ffmpeg 工具进行推流的方法,并在web端实现直播效果。
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并配置把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;
要在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
需要使用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>
这是我试过延迟最小的方法,0.5秒左右,但是非常耗cpu。
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命令封装成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);
});
需要使用 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>