使用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(); });
网友回复