+
38
-

回答

使用ffmpeg.js实现

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>音视频分割与裁剪</title>
  <style>
    body { font-family: Arial, sans-serif; padding: 20px; }
    button { margin: 5px; padding: 8px 16px; }
    #output { margin-top: 20px; }
  </style>
</head>
<body>
  <h1>音视频分割与裁剪</h1>
  <input type="file" id="fileInput" accept="audio/*,video/*" />
  <br />
  <h3>裁剪</h3>
  <label>开始时间 (秒): <input type="number" id="startTime" value="10" min="0" /></label>
  <label>持续时间 (秒): <input type="number" id="duration" value="20" min="1" /></label>
  <button onclick="trimFile()">裁剪文件</button>
  <h3>分割</h3>
  <label>分割间隔 (秒): <input type="number" id="segmentTime" value="10" min="1" /></label>
  <button onclick="splitFile()">分割文件</button>
  <div id="output"></div>

  <!-- 通过 CDN 加载 ffmpeg.wasm -->
  <script src="https://unpkg.com/@ffmpeg/ffmpeg@0.10.1/dist/ffmpeg.min.js"></script>
  <script>
    const { createFFmpeg, fetchFile } = FFmpeg;
    const ffmpeg = createFFmpeg({ log: true }); // 初始化 ffmpeg 实例
    let fileData = null; // 存储上传的文件数据

    // 文件选择事件
    document.getElementById('fileInput').addEventListener('change', async (e) => {
      const file = e.target.files[0];
      if (file) {
        fileData = await file.arrayBuffer(); // 读取文件为 ArrayBuffer
        alert('文件已加载,请选择裁剪或分割操作');
      }
    });

    // 加载 ffmpeg
    async function loadFFmpeg() {
      if (!ffmpeg.isLoaded()) {
        await ffmpeg.load();
        console.log('ffmpeg.wasm 已加载');
      }
    }

    // 裁剪文件
    async function trimFile() {
      const startTime = document.getElementById('startTime').value;
      const duration = document.getElementById('duration').value;
      const outputDiv = document.getElementById('output');

      if (!fileData) {
        alert('请先选择一个文件');
        return;
      }

      try {
        await loadFFmpeg();
        // 将文件写入内存文件系统
        await ffmpeg.FS('writeFile', 'input.mp4', new Uint8Array(fileData));
        // 运行裁剪命令
        await ffmpeg.run(
          '-i', 'input.mp4',
          '-ss', startTime, // 开始时间
          '-t', duration,   // 持续时间
          '-c', 'copy',     // 使用复制模式加快处理
          'output.mp4'
        );
        // 读取输出文件
        const outputData = ffmpeg.FS('readFile', 'output.mp4');
        const outputBlob = new Blob([outputData.buffer], { type: 'video/mp4' });
        const url = URL.createObjectURL(outputBlob);
        // 创建下载链接
        const a = document.createElement('a');
        a.href = url;
        a.download = 'trimmed.mp4';
        a.textContent = '下载裁剪后的文件';
        outputDiv.innerHTML = '';
        outputDiv.appendChild(a);
      } catch (error) {
        console.error('裁剪失败:', error);
        outputDiv.innerHTML = '裁剪失败,请检查控制台';
      }
    }

    // 分割文件
    async function splitFile() {
      const segmentTime = document.getElementById('segmentTime').value;
      const outputDiv = document.getElementById('output');

      if (!fileData) {
        alert('请先选择一个文件');
        return;
      }

      try {
        await loadFFmpeg();
        // 将文件写入内存文件系统
        await ffmpeg.FS('writeFile', 'input.mp4', new Uint8Array(fileData));
        // 运行分割命令
        await ffmpeg.run(
          '-i', 'input.mp4',
          '-f', 'segment',         // 分割格式
          '-segment_time', segmentTime, // 每段时长
          '-reset_timestamps', '1',     // 重置时间戳
          '-c', 'copy',            // 使用复制模式
          'output%03d.mp4'         // 输出文件名模板
        );
        // 读取所有输出文件
        const files = ffmpeg.FS('readdir', '/');
        const outputFiles = files.filter(name => name.startsWith('output'));
        outputDiv.innerHTML = '<h3>分割文件下载链接:</h3>';
        outputFiles.forEach(file => {
          const data = ffmpeg.FS('readFile', file);
          const blob = new Blob([data.buffer], { type: 'video/mp4' });
          const url = URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url;
          a.download = file;
          a.textContent = `下载 ${file}`;
          a.style.display = 'block';
          outputDiv.appendChild(a);
        });
      } catch (error) {
        console.error('分割失败:', error);
        outputDiv.innerHTML = '分割失败,请检查控制台';
      }
    }
  </script>
</body>
</html>

如果出现:ReferenceError: SharedArrayBuffer is not defined

由于 Spectre 和 Meltdown 等安全漏洞,浏览器厂商对 SharedArrayBuffer 的使用进行了限制。

在某些情况下,浏览器会默认禁用 SharedArrayBuffer,除非网站满足特定的安全要求,例如启用跨源隔离(Cross-Origin Isolation)。

可以设置自己的http服务响应跨源隔离

app.use((req, res, next) => {
  res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
  res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
  next();
});

网友回复

我知道答案,我要回答