如何在HTML Canvas中并排显示多视频?解决step函数绑定问题
多视频Canvas渲染解决方案
核心思路
利用闭包或类封装,让每个视频对应的渲染回调能访问自身的视频元素、视图参数和动画句柄,解决requestVideoFrameCallback回调中无法通过this访问视频的问题。
实现代码
方案1:闭包封装单视频渲染逻辑
const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); // 存储所有视频实例,方便后续单独控制 const videoInstances = []; function createVideoRenderer(videoSrc, left, top, width, height) { const video = document.createElement("video"); let animationHandle = null; // 闭包捕获当前视频、视图参数和动画句柄 function step() { ctx.drawImage(video, left, top, width, height); animationHandle = video.requestVideoFrameCallback(step); } video.onloadeddata = function () { video.playbackRate = 1; video.play(); step(); }; video.src = videoSrc; // 返回控制方法,支持单独暂停/播放 const instance = { video, pause() { video.pause(); if (animationHandle) { video.cancelVideoFrameCallback(animationHandle); animationHandle = null; } }, play() { video.play(); if (!animationHandle) { step(); } } }; videoInstances.push(instance); return instance; } // 创建多个并排视频实例 createVideoRenderer("video1.mp4", 0, 0, 320, 240); createVideoRenderer("video2.mp4", 330, 0, 320, 240); createVideoRenderer("video3.mp4", 0, 250, 320, 240);
方案2:类封装(结构更清晰)
const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); class CanvasVideoRenderer { constructor(videoSrc, left, top, width, height) { this.video = document.createElement("video"); this.left = left; this.top = top; this.width = width; this.height = height; this.animationHandle = null; this.video.onloadeddata = () => { this.video.playbackRate = 1; this.video.play(); this.step(); }; this.video.src = videoSrc; } step() { ctx.drawImage(this.video, this.left, this.top, this.width, this.height); this.animationHandle = this.video.requestVideoFrameCallback(() => this.step()); } pause() { this.video.pause(); if (this.animationHandle) { this.video.cancelVideoFrameCallback(this.animationHandle); this.animationHandle = null; } } play() { this.video.play(); if (!this.animationHandle) { this.step(); } } } // 实例化多个视频 const video1 = new CanvasVideoRenderer("video1.mp4", 0, 0, 320, 240); const video2 = new CanvasVideoRenderer("video2.mp4", 330, 0, 320, 240); // 单独控制示例:暂停第一个视频 // video1.pause();
关键说明
- 每个视频的
step回调通过闭包或类实例上下文,直接访问对应视频元素、视图位置和动画句柄,无需依赖全局或局部共享变量。 - 每个实例提供独立的
pause/play方法,暂停时会取消对应的视频帧回调,避免无效渲染。 - 所有视频共享同一个Canvas上下文,按指定坐标绘制到对应区域,实现并排显示效果。
内容的提问来源于stack exchange,提问作者Steve Brooker
相关产品推荐
相关产品推荐

