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

Electron中Node.js写入Blob数据生成MP4文件损坏问题

问题分析与解决方案

可能的问题点

  1. 数据引用错误
    你在渲染进程中发送的是arrayRecord.current[0].data.video,但实际收集HLS buffer的是dataStream.current[type],两者如果不是同一数据源,会导致写入的数据不完整或错误。

  2. IPC传递数组的序列化风险
    Electron的IPC传递拆分的Uint8Array数组时,可能因序列化/反序列化导致数据丢失或结构损坏,尤其是大数组场景。

  3. 文件格式不匹配
    HLS的分片是TS(MPEG-2 Transport Stream)格式,直接将其保存为MP4后缀,部分播放器无法正确解析,会显示文件损坏。原锚点下载能播放可能是播放器兼容了TS格式,但严格来说需要对应正确的文件类型。

  4. 主进程冗余的Blob转换
    主进程中先将Uint8Array转成Blob再转成Buffer写入,多了一次转换步骤,增加了数据出错的概率。


具体修复步骤

1. 修正渲染进程的数据引用

将发送数据的来源改为实时收集的dataStream,确保传递的是正确的录制数据:

// 渲染进程 useEffect 内的 sendStreamData 函数
const sendStreamData = async () => {
  await window.electronAPI.handleFileDownload({
    video: dataStream.current.video,
    audio: dataStream.current.audio,
    audiovideo: []
  });
};

2. 优化IPC数据传递(可选但推荐)

在渲染进程先将buffer数组合并为单个Uint8Array后再传递,减少序列化风险:

// 渲染进程新增合并函数
const concatUint8Arrays = (arrays: Uint8Array[]) => {
  const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
  const merged = new Uint8Array(totalLength);
  let offset = 0;
  arrays.forEach(arr => {
    merged.set(arr, offset);
    offset += arr.length;
  });
  return merged;
};

// 修改 sendStreamData
const sendStreamData = async () => {
  const mergedVideo = concatUint8Arrays(dataStream.current.video);
  const mergedAudio = concatUint8Arrays(dataStream.current.audio);
  await window.electronAPI.handleFileDownload({
    video: mergedVideo,
    audio: mergedAudio,
    audiovideo: []
  });
};

3. 修正主进程的文件写入逻辑

直接使用传递的Buffer(Electron会自动将Uint8Array转为Buffer)写入,去掉冗余的Blob转换,同时保存为正确的TS格式:

// 主进程 downloadVideo 函数
const downloadVideo = (videoData: Buffer) => {
  // 先保存为TS文件,验证是否能播放
  const outputPath = "out/video.ts";
  fs.writeFileSync(outputPath, videoData);
};

// 如果接收的是未合并的数组,使用Buffer合并
const concatBuffers = (buffers: Buffer[]) => {
  const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0);
  const merged = Buffer.alloc(totalLength);
  let offset = 0;
  buffers.forEach(buf => {
    buf.copy(merged, offset);
    offset += buf.length;
  });
  return merged;
};

// 对应接收数组的场景
const downloadVideo = (videoData: Buffer[]) => {
  const mergedBuffer = concatBuffers(videoData);
  const outputPath = "out/video.ts";
  fs.writeFileSync(outputPath, mergedBuffer);
};

4. (可选)转封装为MP4

如果需要标准MP4格式,可使用fluent-ffmpeg库将TS文件转成MP4:

# 先安装依赖
npm install fluent-ffmpeg
import ffmpeg from 'fluent-ffmpeg';

const convertTsToMp4 = (tsPath: string, mp4Path: string) => {
  ffmpeg(tsPath)
    .output(mp4Path)
    .on('end', () => console.log('转封装完成'))
    .on('error', err => console.error('转封装失败:', err))
    .run();
};

验证步骤

  1. 在渲染进程中新增测试下载,确认数据本身是否正常:
// 渲染进程内添加测试函数
const testRenderDownload = () => {
  const mergedVideo = concatUint8Arrays(dataStream.current.video);
  const blob = new Blob([mergedVideo], { type: "video/MP2T" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'test.ts';
  a.click();
  URL.revokeObjectURL(url);
};

如果这个测试文件能正常播放,说明数据收集没问题,问题出在IPC或主进程写入环节。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 05:45:38