实时录制摄像头视频无时长,无法拖拽跳转问题求助
问题:摄像头实时录制生成的MP4无时长,无法拖拽播放
我搭建了一个服务器端实时录制摄像头的网站,通过WebSocket将摄像头数据传输到Node.js服务器,录制功能正常,但生成的视频没有时长信息,只能逐秒播放,无法拖拽进度条(示例如下):

服务器保存视频的代码如下:
server.on("connection", (socket) => { console.log("Client connected"); let writeStream = null; let id = Date.now(); let filename = `${folderStream}/video-${id}.${extensionFile}`; // example : ./video/video-1620000000000.mp4 socket.on("message", (message) => { if (!writeStream) { console.log("Stream started"); writeStream = fs.createWriteStream(filename); } writeStream.write(message); }); socket.on("close", () => { console.log("Stream closed"); writeStream.end(); }); });
我试过用FFmpeg,但因为是单个完整文件而非分段文件,问题仍未解决,求技术帮助。
核心原因
直接通过WebSocket传输并写入的摄像头数据流,本质是原始的H.264裸流或未完整封装的MP4片段。MP4文件的时长、索引等关键元数据存储在moov原子块中,默认会被写入到文件末尾。但你直接流式写入后关闭文件,播放器无法读取到完整的元数据,因此无法识别时长和支持拖拽操作。
解决方案
方案1:用FFmpeg修复已生成的视频文件
即使是单个完整文件,FFmpeg也能快速重新封装MP4,补全缺失的元数据。执行以下命令:
ffmpeg -i input.mp4 -c copy -movflags faststart output.mp4
-c copy:直接复制音视频流,不重新编码,处理速度极快-movflags faststart:将moov原子移到文件开头,同时补全时长等元数据
方案2:实时用FFmpeg转码/封装(推荐)
不要直接写入原始流,而是将WebSocket接收到的数据通过管道传给FFmpeg,让它实时完成标准MP4封装,生成的文件自带完整元数据。
修改Node.js代码示例:
const { spawn } = require('child_process'); const fs = require('fs'); server.on("connection", (socket) => { console.log("Client connected"); let id = Date.now(); let filename = `${folderStream}/video-${id}.mp4`; // 启动FFmpeg进程,实时封装MP4 const ffmpegProcess = spawn('ffmpeg', [ '-i', '-', // 从标准输入读取原始流 '-c:v', 'copy', // 复制视频流(需前端传输H.264编码的流) '-movflags', 'faststart+frag_keyframe+empty_moov', // 实时分段封装,保证中途可播放 filename ]); socket.on("message", (message) => { // 将WebSocket数据传给FFmpeg的标准输入 ffmpegProcess.stdin.write(message); }); socket.on("close", () => { console.log("Stream closed"); // 关闭FFmpeg输入,触发封装收尾 ffmpegProcess.stdin.end(); ffmpegProcess.on('exit', () => { console.log(`视频文件已生成:${filename}`); }); }); // 处理FFmpeg的错误输出 ffmpegProcess.stderr.on('data', (data) => { console.error(`FFmpeg错误:${data.toString()}`); }); });
注意:如果前端传输的是VP8/VP9等非H.264编码的流,需将参数改为-c:v libx264转码为H.264,保证MP4兼容性。
方案3:前端先做标准封装
如果前端用MediaRecorder录制摄像头流,可配置输出标准MP4格式,减少后端处理压力:
// 前端MediaRecorder配置示例 const mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"' // 指定H.264+AAC编码 });
前端传输的标准MP4流,后端写入后再用方案1的FFmpeg命令修复即可。
内容的提问来源于stack exchange,提问作者Catif
相关产品推荐
相关产品推荐

