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

如何用JavaScript在浏览器端合并HLS流音视频并单文件下载?

浏览器端纯JS合并HLS音视频流并下载

原代码只能分别下载音视频文件,因为HLS的音视频是分开的分片流,直接拼接二进制数据没法生成可播放的单个媒体文件,得借助FFmpeg.wasm(浏览器端的FFmpeg移植版)来处理容器合并。

步骤说明

  1. 引入FFmpeg.wasm依赖
    在HTML中添加CDN链接:

    <script src="https://unpkg.com/@ffmpeg/ffmpeg@0.10.1/dist/ffmpeg.min.js"></script>
    
  2. 修改原代码核心逻辑

    • 保留原有的音视频数据收集逻辑
    • 将stopRecord函数改为用FFmpeg合并音视频后再下载

完整修改后的代码

var arrayRecord = [];
// 初始化FFmpeg实例
const { createFFmpeg, fetchFile } = FFmpeg;
const ffmpeg = createFFmpeg({ log: true });

function arrayConcat(inputArray) {
    var totalLength = inputArray.reduce(function (prev, cur) {
        return prev + cur.length
    }, 0);
    var result = new Uint8Array(totalLength);
    var offset = 0;
    inputArray.forEach(function (element) {
        result.set(element, offset);
        offset += element.length;
    });
    return result;
}

function saveAs(blob, filename) {
    var url = URL.createObjectURL(blob);
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    a.href = url;
    a.download = filename;
    a.click();
    window.URL.revokeObjectURL(url);
}

async function stopRecord() {
    // 加载FFmpeg核心
    if (!ffmpeg.isLoaded()) {
        await ffmpeg.load();
    }

    arrayRecord.forEach(async function (item) {
        // 将收集的音视频数据转为Blob
        const videoBlob = new Blob([arrayConcat(item.data['video'])], { type: 'video/mp4' });
        const audioBlob = new Blob([arrayConcat(item.data['audio'])], { type: 'audio/mp4' });

        // 写入FFmpeg虚拟文件系统
        ffmpeg.FS('writeFile', 'input-video.mp4', await fetchFile(videoBlob));
        ffmpeg.FS('writeFile', 'input-audio.mp4', await fetchFile(audioBlob));

        // 执行合并命令:将音视频合并为output.mp4
        await ffmpeg.run('-i', 'input-video.mp4', '-i', 'input-audio.mp4', '-c:v', 'copy', '-c:a', 'copy', 'output.mp4');

        // 读取合并后的文件并下载
        const data = ffmpeg.FS('readFile', 'output.mp4');
        const outputBlob = new Blob([data.buffer], { type: 'video/mp4' });
        saveAs(outputBlob, "merged-stream.mp4");

        // 清理虚拟文件和HLS实例
        ffmpeg.FS('unlink', 'input-video.mp4');
        ffmpeg.FS('unlink', 'input-audio.mp4');
        ffmpeg.FS('unlink', 'output.mp4');
        item.hls.destroy();
    });
}

function startRecord() {
    var video = document.getElementById('video');
    var dataStream = {
        'video': [],
        'audio': []
    };
    var hls = new Hls();
    hls.loadSource("Your playlist"); // 替换成你的m3u8地址
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED, function () {
        video.play();
        hls.on(Hls.Events.BUFFER_APPENDING, function (event, data) {
            console.log("appending");
            dataStream[data.type].push(data.data);
        });
    });
    arrayRecord.push({
        hls: hls,
        data: dataStream
    });
    video.onended = function (e) {
        stopRecord()
    }
}

注意事项

  • FFmpeg.wasm体积较大,首次加载会有延迟
  • 跨域问题:如果m3u8流和页面不同域,需要目标服务器配置CORS
  • 长时长直播流会占用较多内存,因为所有分片数据都存在内存中

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 07:23:20