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

如何在Node.js服务器中实时保存摄像头流及Blob块为视频文件

如何在Node.js服务器中实时保存摄像头流及Blob块为单个视频文件

首先得指出你当前代码里的核心问题:axios默认会把请求体序列化成JSON,所以你传的Uint8Array会被转成普通的数字数组,服务端拿到的根本不是二进制数据,自然没法直接拼成视频文件。接下来我给你一步步调整代码,实现完整的录制保存流程。

第一步:修正客户端的Blob发送方式

咱们要直接发送原始的Blob二进制数据,而不是转成Uint8Array再用JSON传输。修改你的postBlob和新增录制结束的函数:

// 发送单个Blob数据块
postBlob = async (blob) => {
  try {
    await axios.post('/api', blob, {
      headers: {
        'Content-Type': blob.type, // 用Blob自带的类型,比如video/webm
        'X-Chunk-Type': 'video-data' // 自定义头标记这是视频数据块
      }
    });
  } catch (err) {
    console.error('数据块上传失败:', err);
  }
};

// 录制结束时给服务端发结束信号
finishRecording = async () => {
  try {
    const res = await axios.post('/api/end-recording', {}, {
      headers: {
        'X-Chunk-Type': 'end-signal'
      }
    });
    console.log('录制完成,文件已保存:', res.data.filePath);
  } catch (err) {
    console.error('结束录制请求失败:', err);
  }
};

这样客户端就会直接把Blob的二进制内容发出去,服务端能拿到原始的视频数据。

第二步:服务端实现分块写入与结束处理

服务端需要用可写流来持续接收并写入数据块,直到收到结束信号再关闭流,生成完整的视频文件。这里用express.raw()来处理二进制数据,而不是默认的JSON解析:

const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();

// 配置express处理视频类型的二进制数据
app.use(express.raw({ type: 'video/*' }));

// 全局维护一个可写流(单用户场景,多用户需用会话/ID区分文件)
let videoWriteStream = null;
const outputDir = path.join(__dirname, 'recorded-videos');
// 确保输出目录存在
if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir);

// 处理视频数据块
app.post('/api', (req, res) => {
  const chunkType = req.headers['x-chunk-type'];

  if (chunkType === 'video-data') {
    // 如果还没创建写入流,初始化一个新文件
    if (!videoWriteStream) {
      const fileName = `video-${Date.now()}.webm`;
      const filePath = path.join(outputDir, fileName);
      videoWriteStream = fs.createWriteStream(filePath, { flags: 'w' });
      
      // 监听写入错误,避免程序崩溃
      videoWriteStream.on('error', (err) => {
        console.error('文件写入错误:', err);
        videoWriteStream = null;
      });
    }

    // 将当前数据块写入文件
    videoWriteStream.write(req.body);
    res.status(200).json({ status: 'chunk-received' });
  } else {
    res.status(400).json({ error: '无效的数据块类型' });
  }
});

// 处理录制结束信号
app.post('/api/end-recording', (req, res) => {
  if (videoWriteStream) {
    videoWriteStream.end(() => {
      const filePath = videoWriteStream.path;
      console.log('视频录制完成,文件路径:', filePath);
      videoWriteStream = null; // 重置流,准备下一次录制
      res.status(200).json({ status: 'success', filePath });
    });
  } else {
    res.status(400).json({ error: '没有正在进行的录制' });
  }
});

app.listen(3000, () => {
  console.log('服务器运行在 http://localhost:3000');
});

关键注意点

  • 多用户场景适配:上面的代码是单用户版本,如果要支持多个用户同时录制,需要给每个用户分配唯一的文件(比如用用户ID、会话ID作为文件名的一部分),避免文件被覆盖。
  • 视频格式兼容性:确保客户端录制的视频格式是WebM或者MP4这类流式拼接友好的格式,不然拼接后的文件可能无法播放。
  • 错误处理:一定要给可写流加上error监听,防止磁盘满、权限不足等问题导致程序崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:40:11