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

如何将带视频与文字的FabricJS画布导出为带声音的MP4?

解决方案:FabricJS画布导出为带音频的MP4

嘿,我懂你现在的痛点——FabricJS本身没提供直接导出视频的功能,但我们可以用浏览器的MediaRecorder API结合Canvas捕获能力,实现你要的「原视频背景+叠加文字+保留原音频」的MP4导出效果。下面是具体的实现步骤和代码:

核心思路

  1. 借助FabricJS的实时渲染,把画布内容持续绘制到可捕获的Canvas流中
  2. 提取原视频的音频轨道,和Canvas的视频流合并成一个完整的MediaStream
  3. 用MediaRecorder录制这个合并后的流,最终导出为MP4文件

修改后的完整代码

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.2.3/fabric.min.js"></script>
</head>
<body>
    <button id="play">play</button>
    <button id="exportvideo">Export as video</button>
    <canvas id="c" width="480" height="360"></canvas>
    <video crossorigin="anonymous" id="video1" style="display: none" class="canvas-img" width="480" height="360">
        <source id="video_src1" src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" type="video/mp4">
    </video>

    <script>
        $(document).ready(function() {
            let canvas = new fabric.Canvas('c');
            canvas.setWidth(480);
            canvas.setHeight(360);
            let video1El = document.getElementById('video1');
            let video1 = new fabric.Image(video1El, { left: 0, top: 0 });
            canvas.add(video1);
            video1El.load();

            // 保留原有播放按钮逻辑
            $(document.body).on('click', '#play', function(){
                let iText = new fabric.IText("sample text", { 
                    fill: 'red', 
                    fontSize: 60, 
                    left: 10, 
                    top: 10 
                });
                canvas.add(iText);
                video1El.play();
            });

            // 导出视频核心逻辑
            $(document.body).on('click', '#exportvideo', async function(){
                // 先检查视频是否在播放
                if (video1El.paused) {
                    alert("请先点击播放按钮启动视频!");
                    return;
                }

                // 1. 捕获FabricJS画布的视频流(30帧/秒,可按需调整)
                const canvasStream = canvas.captureStream(30);

                // 2. 提取原视频的音频轨道并合并到视频流
                const audioTrack = video1El.captureStream().getAudioTracks()[0];
                if (audioTrack) {
                    canvasStream.addTrack(audioTrack);
                }

                // 3. 配置MediaRecorder为MP4格式
                const recordOptions = { mimeType: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"' };
                let mediaRecorder = new MediaRecorder(canvasStream, recordOptions);
                let recordedChunks = [];

                // 4. 收集录制的视频数据
                mediaRecorder.ondataavailable = function(e) {
                    if (e.data.size > 0) {
                        recordedChunks.push(e.data);
                    }
                };

                // 5. 录制结束后生成下载链接
                mediaRecorder.onstop = function() {
                    const videoBlob = new Blob(recordedChunks, { type: 'video/mp4' });
                    const downloadUrl = URL.createObjectURL(videoBlob);
                    const downloadLink = document.createElement('a');
                    downloadLink.href = downloadUrl;
                    downloadLink.download = 'fabric-canvas-export.mp4';
                    downloadLink.click();
                    URL.revokeObjectURL(downloadUrl); // 释放浏览器资源
                };

                // 6. 启动录制(示例录制5秒,可改成监听视频结束事件)
                mediaRecorder.start();
                alert("开始录制,5秒后自动下载!");
                setTimeout(() => {
                    mediaRecorder.stop();
                }, 5000);

                // 可选:监听视频自然结束,自动停止录制
                // video1El.onended = function() {
                //     mediaRecorder.stop();
                // };
            });

            // 保持FabricJS的实时渲染循环
            fabric.util.requestAnimFrame(function render() {
                canvas.renderAll();
                fabric.util.requestAnimFrame(render);
            });
        });
    </script>
</body>
</html>

关键细节说明

  • 跨域处理:你的视频标签已经加了crossorigin="anonymous",这非常关键!如果没有这个设置,浏览器会因为跨域限制阻止捕获视频流,确保视频服务器允许跨域访问。
  • 帧率调整:canvas.captureStream(30)中的30是录制帧率,可根据性能需求调整(比如24帧更接近电影播放效果)。
  • 音频合并:通过video1El.captureStream().getAudioTracks()提取原视频的音频轨道,合并到Canvas流中,这样导出的视频就能保留原声音。
  • 录制时长:示例用setTimeout设置了5秒录制,你可以替换成监听video1El.onended事件,让录制在视频自然播放结束后自动停止。

注意事项

  • 浏览器兼容性:MediaRecorder API在Chrome、Firefox上支持良好,Safari需要14.1以上版本,部分编码格式可能需要根据浏览器调整。
  • 性能优化:如果画布内容复杂(比如多个动画图层),高帧率录制可能会卡顿,可适当降低帧率或简化画布内容。
  • 编码格式:示例中的mimeType是通用的MP4编码配置,如果出现录制失败,可以尝试调整编码参数适配目标浏览器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:08:25