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

如何让HTML5 video在Node.js+Electron中直接播放内存解密的MP4数据

加密MP4内存播放改造方案

两种实现方案均无需写入本地磁盘,直接在内存中完成解密播放:

方案1:全量解密后生成Blob URL(适合中小体积视频)

无需转码、实现简单,性能远高于当前的base64实现方案,直接将内存中的解密数据生成临时访问地址赋值给播放器即可。

const crypto = require('crypto');
const fs = require('fs');

const key = "12345678asdfghjk";
const keyBuf = Buffer.from(key);
const inputStream = fs.createReadStream(file + "c");
const cipher = crypto.createDecipher("aes-128-cbc", keyBuf); // 建议后续替换为createDecipheriv
const decryptedChunks = [];

inputStream.on('data', (data) => {
  const buf = cipher.update(data);
  decryptedChunks.push(buf);
});

inputStream.on('end', () => {
  try {
    const finalBuf = cipher.final();
    decryptedChunks.push(finalBuf);
    // 拼接所有解密后的buffer
    const fullDecryptedBuf = Buffer.concat(decryptedChunks);
    // 转成Blob生成内存临时访问地址
    const videoBlob = new Blob([fullDecryptedBuf], { type: 'video/mp4' });
    const videoUrl = URL.createObjectURL(videoBlob);
    
    const introVideo = document.getElementById("introVideo");
    introVideo.src = videoUrl;
    introVideo.play();
    
    // 视频播放完成后释放内存,避免泄漏
    introVideo.onended = () => {
      URL.revokeObjectURL(videoUrl);
    };
  } catch (e) {
    console.log(e);
  }
});

方案2:边解密边播放(适合大体积视频,低内存占用)

基于MediaSource Extensions API实现流式播放,不用等整个视频解密完成,解密一部分就喂给播放器一部分,内存占用稳定在百KB级别,适合GB级大视频。

注意:该方案需要视频为碎片化MP4(fMP4)格式,普通MP4需要先转成碎片化格式才能流式加载。

const crypto = require('crypto');
const fs = require('fs');

const key = "12345678asdfghjk";
const keyBuf = Buffer.from(key);
// 按1M切片读取文件
const inputStream = fs.createReadStream(file + "c", { highWaterMark: 1024 * 1024 });
const cipher = crypto.createDecipher("aes-128-cbc", keyBuf);
const introVideo = document.getElementById("introVideo");
const mediaSource = new MediaSource();

introVideo.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', () => {
  // 替换为你视频对应的实际编码格式
  const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
  let isStreamEnd = false;
  const bufferQueue = [];

  // 缓冲队列处理逻辑
  const processQueue = () => {
    if (bufferQueue.length && !sourceBuffer.updating) {
      sourceBuffer.appendBuffer(bufferQueue.shift());
    } else if (isStreamEnd && bufferQueue.length === 0) {
      mediaSource.endOfStream();
    }
  };

  sourceBuffer.addEventListener('updateend', processQueue);

  // 解密数据喂给播放器
  inputStream.on('data', (data) => {
    const decrypted = cipher.update(data);
    bufferQueue.push(decrypted);
    processQueue();
  });

  inputStream.on('end', () => {
    try {
      const finalBuf = cipher.final();
      bufferQueue.push(finalBuf);
      isStreamEnd = true;
      processQueue();
    } catch (e) {
      console.log(e);
    }
  });

  // 播放结束释放内存
  introVideo.onended = () => {
    URL.revokeObjectURL(introVideo.src);
  };
});

通用注意事项

  • 原代码中使用的new Buffer()和crypto.createDecipher()均为Node.js废弃API,建议后续替换为Buffer.from()和crypto.createDecipheriv(),显式传入16字节初始化向量(IV)提升安全性
  • 所有生成的objectURL使用完成后必须调用URL.revokeObjectURL释放,否则会出现内存泄漏问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 22:15:03