Node.js中写入前如何压缩Buffer/Blob格式的视频文件体积
解决方案:服务端实时编码压缩直播流
问题根源
你当前的服务端代码只是简单将客户端传来的VP9编码WebM片段直接打包成MP4,这既不符合MP4封装规范(可能导致文件无法正常播放),也没有做任何压缩优化。要实现写入磁盘前的体积缩减,必须在服务端对接收到的媒体流进行实时转码+重新编码,同时调整编码参数控制体积。
一、客户端侧前置优化(可选,减轻服务端压力)
如果业务允许,先在客户端降低原始流的码率或分辨率,从源头减少数据量:
recorder = new MediaRecorder(canvasStream, { mimeType: 'video/webm;codecs=vp9', videoBitsPerSecond: 1.5 * 1024 * 1024, // 从3Mbps降到1.5Mbps,根据场景调整 // 可选:限制分辨率,比如强制720p // videoConstraints: { width: 1280, height: 720 } });
二、服务端核心方案:用FFmpeg实时转码压缩
借助FFmpeg(专业音视频处理工具)实现WebSocket流的实时编码、压缩与封装,直接输出体积优化后的MP4文件。
1. 前置准备
确保服务端环境安装FFmpeg:
- Ubuntu/Debian:
apt install ffmpeg - CentOS/RHEL:
yum install ffmpeg - Windows:下载官方二进制文件并配置环境变量
2. 服务端代码实现
const { spawn } = require('child_process'); const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', (ws) => { // 启动FFmpeg子进程,实时处理流并写入压缩后的MP4 const ffmpeg = spawn('ffmpeg', [ '-i', '-', // 从标准输入读取WebSocket传来的流 '-c:v', 'libx264', // 使用H.264编码器(兼容性好,压缩效率高) '-crf', '28', // 恒定质量参数:0-51,值越大体积越小,28为中等质量平衡点 '-preset', 'medium', // 编码速度/压缩比平衡:fast(快)→ slow(压缩更好但慢) '-c:a', 'aac', // 音频用AAC编码(若无音频可替换为'-an') '-b:a', '128k', // 音频码率 '-f', 'mp4', // 输出格式为MP4 '-movflags', '+faststart', // 让MP4支持边下载边播放 'foo_compressed.mp4' // 最终输出文件 ]); // 监听FFmpeg错误输出,用于排查问题 ffmpeg.stderr.on('data', (data) => { console.error(`FFmpeg日志: ${data.toString()}`); }); // 接收WebSocket数据,写入FFmpeg标准输入 ws.on('message', (message) => { // 解析客户端的数据包(需与你的pack方法对应,比如用msgpack或自定义二进制解析) const { type, data } = unpack(message); if (type === 'REC') { ffmpeg.stdin.write(Buffer.from(data)); } }); // 连接断开时结束FFmpeg进程 ws.on('close', () => { ffmpeg.stdin.end(); console.log('WebSocket连接关闭,FFmpeg转码结束'); }); }); // 示例:与客户端pack对应的解包函数(根据你的实际序列化方式调整) function unpack(packedData) { // 假设客户端用JSON+ArrayBuffer转换,这里做反向解析 const decoded = JSON.parse(packedData.toString().slice(0, -1)); const buffer = packedData.slice(packedData.toString().lastIndexOf('}') + 1); decoded.data = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); return decoded; }
3. 参数优化说明
- CRF值:
-crf 28是H.264的推荐中等质量值,每增加6,文件体积减半;每减少6,体积翻倍。可根据画质需求调整(23-30区间常用)。 - Preset参数:
-preset medium是默认平衡选项,若服务器性能充足,可改为slow或slower获得更好压缩比;若性能有限,用fast或veryfast。 - 分辨率调整:如需强制降分辨率,添加参数
-vf scale=1280:720(转720p),或-vf scale=-2:720(保持宽高比,高度固定720)。 - 无音频场景:去掉
-c:a和-b:a,添加-an参数禁用音频处理。
三、关键注意事项
- 客户端的
pack方法需确保二进制数据能被服务端正确解析,避免序列化/反序列化丢失数据。 - FFmpeg进程需正确处理流的结束(WebSocket断开时调用
stdin.end()),否则输出文件会损坏。 - 若客户端发送的是VP9编码流,FFmpeg会自动解码后重新编码为H.264,无需额外配置。
内容的提问来源于stack exchange,提问作者Hypothesis
相关产品推荐
相关产品推荐

