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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 01:52:21