Electron中Node.js写入Blob数据生成MP4文件损坏问题
问题分析与解决方案
可能的问题点
数据引用错误
你在渲染进程中发送的是arrayRecord.current[0].data.video,但实际收集HLS buffer的是dataStream.current[type],两者如果不是同一数据源,会导致写入的数据不完整或错误。IPC传递数组的序列化风险
Electron的IPC传递拆分的Uint8Array数组时,可能因序列化/反序列化导致数据丢失或结构损坏,尤其是大数组场景。文件格式不匹配
HLS的分片是TS(MPEG-2 Transport Stream)格式,直接将其保存为MP4后缀,部分播放器无法正确解析,会显示文件损坏。原锚点下载能播放可能是播放器兼容了TS格式,但严格来说需要对应正确的文件类型。主进程冗余的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(); };
验证步骤
- 在渲染进程中新增测试下载,确认数据本身是否正常:
// 渲染进程内添加测试函数 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
相关产品推荐
相关产品推荐

