项目需求就是,需要将视频推送到浏览器展示的同时推送到后端服务进行图像分析,为了保证前后端接收到的视频流是同一时间段的,所以采取搭建node-media-server作为中间直播平台,前端直接获取flv流展示,后端获取RTMP进行分析,视频较大,对硬件要求比较高,测试机32G ,I7-12700K
服务端获取RTMP地址:
rtmp://node-media-server IP/live/${path.parse(videoPath).name}
前端播放地址: POST是下面代码中http的端口
http://node-media-server IP:post/live/A1.flv
代码
const fs = require('fs');
const path = require('path');
const spawn = require('child_process').spawn;
const async = require('async');
const NodeMediaServer = require('node-media-server');
// 创建node-media-server实例
const nmsConfig = {
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
ping: 60,
ping_timeout: 30
},
http: {
port: 8000,
mediaroot: './media',
allow_origin: '*'
}
};
const nms = new NodeMediaServer(nmsConfig);
nms.run();
// 根据指定的目录和文件类型创建要推流的文件列表
const videoDir = '';
const allowedExtensions = ['.mp4', '.avi', '.mov'];
const fileList = [];
fs.readdirSync(videoDir).forEach(file => {
const fileExtension = path.extname(file);
if (allowedExtensions.includes(fileExtension)) {
fileList.push(path.join(videoDir, file));
}
});
if (!fileList.length) {
console.log('No video files found!');
process.exit(1);
}
// 配置FFmpeg推流命令行参数
const ffmpegCommand = `ffmpeg -re -stream_loop -1 -i "$input$" -c:v libx264 -b:v 1M -preset veryfast -maxrate 1.2M -bufsize 1M -c:a aac -b:a 128k -f flv "$output$"`;
const ffmpegEscapeMap = { '$input$': '', '$output$': '' };
let index = 0;
const maxIndex = fileList.length - 1;
async.each(fileList, (videoPath, callback) => {
// 构建FFmpeg命令行参数
ffmpegEscapeMap['$input$'] = videoPath;
// node-media-server IP即可,无需填写端口默认端口1935 服务端获取的RTMP流也是这个地址
ffmpegEscapeMap['$output$'] = `rtmp://node-media-server IP/live/${path.parse(videoPath).name}`;
const output = `rtmp://node-media-server IP/live/${path.parse(videoPath).name}`;
const command = ffmpegCommand.replace(/\$\w+\$/g, m => ffmpegEscapeMap[m]);
console.log(`Starting streaming for file: ${videoPath}...`);
// 调用FFmpeg推流
const ffProcess = spawn("ffmpeg"
,['-re','-stream_loop','-1','-i',videoPath,'-c:v','libx264','-b:v','1M','-preset','veryfast','-maxrate','1.2M',
'-bufsize','1M','-c:a','aac','-b:a','128k','-f','flv',output]
, { detached: true });
// 捕捉事件
ffProcess.on('exit', () => {
console.log(`Stop streaming for file: ${videoPath}.`);
if (++index > maxIndex) {
index = 0; // 循环推流
}
});
ffProcess.on('close', code => {
console.log(`Process ${path.parse(videoPath).name} exited with code ${code}`);
if (++index > maxIndex) {
index = 0; // 循环推流
}
});
ffProcess.stderr.on('data', (data) => {
console.log(`${videoPath}: ${data.toString()}`);
});
callback();
})
console.log(`Started pushing ${fileList.length} stream(s) to node-media-server on rtmp://192.168.2.129:1935/live/.`);