You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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参数禁用音频处理。

三、关键注意事项

  1. 客户端的pack方法需确保二进制数据能被服务端正确解析,避免序列化/反序列化丢失数据。
  2. FFmpeg进程需正确处理流的结束(WebSocket断开时调用stdin.end()),否则输出文件会损坏。
  3. 若客户端发送的是VP9编码流,FFmpeg会自动解码后重新编码为H.264,无需额外配置。

内容的提问来源于stack exchange,提问作者Hypothesis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 20:40:25