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


