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

如何修改Chrome画中画扩展实现无固定宽高比调整窗口?

修改Google PIP扩展实现自由拉伸窗口(无固定宽高比)

要实现PIP窗口自由拉伸不锁宽高比,你不能只改现有的ResizeObserver逻辑——因为Chrome原生的Picture-in-Picture API会强制保持视频元素的固有宽高比,直接操作video元素的PIP绕不开这个限制。得换个思路:用Canvas中转视频流,把Canvas放进PIP窗口,这样就能自由调整尺寸了。

具体修改方案

替换原扩展中requestPictureInPicture和maybeUpdatePictureInPictureVideo函数,同时添加必要的辅助逻辑:

// 全局变量:中转用Canvas、当前关联视频、帧绘制定时器
let pipCanvas = null;
let currentPipVideo = null;
let drawFrameTimer = null;

async function requestPictureInPicture(video) {
  // 清理之前的PIP资源
  if (pipCanvas) cleanupPipResources();

  currentPipVideo = video;
  // 创建隐藏的Canvas元素
  pipCanvas = document.createElement('canvas');
  pipCanvas.style.display = 'none';
  document.body.appendChild(pipCanvas);

  // 初始同步视频尺寸到Canvas
  updateCanvasSize(video.videoWidth, video.videoHeight);

  // 绑定视频播放状态监听,控制帧绘制
  video.addEventListener('play', startDrawingFrames);
  video.addEventListener('pause', stopDrawingFrames);
  video.addEventListener('ended', stopDrawingFrames);

  // 请求Canvas进入PIP模式
  await pipCanvas.requestPictureInPicture();
  pipCanvas.setAttribute('__pip__', true);

  // 监听PIP退出事件,清理资源
  pipCanvas.addEventListener('leavepictureinpicture', cleanupPipResources, { once: true });

  // 监听Canvas尺寸变化(PIP窗口被拉伸时)
  new ResizeObserver(handlePipResize).observe(pipCanvas);
}

// 处理PIP窗口拉伸:直接同步Canvas绘制尺寸,不保持比例
function handlePipResize(entries) {
  const canvas = entries[0].target;
  const size = entries[0].contentBoxSize[0];
  canvas.width = size.inlineSize;
  canvas.height = size.blockSize;
}

// 更新Canvas基础尺寸
function updateCanvasSize(width, height) {
  if (pipCanvas) {
    pipCanvas.width = width;
    pipCanvas.height = height;
  }
}

// 开始定时绘制视频帧到Canvas(拉伸填充)
function startDrawingFrames() {
  if (!drawFrameTimer && currentPipVideo && pipCanvas) {
    drawFrameTimer = setInterval(() => {
      const ctx = pipCanvas.getContext('2d');
      // 拉伸视频帧填充整个Canvas,忽略原宽高比
      ctx.drawImage(currentPipVideo, 0, 0, pipCanvas.width, pipCanvas.height);
    }, 16); // 约60fps的绘制频率
  }
}

// 停止帧绘制
function stopDrawingFrames() {
  if (drawFrameTimer) {
    clearInterval(drawFrameTimer);
    drawFrameTimer = null;
  }
}

// 清理所有PIP相关资源,避免内存泄漏
function cleanupPipResources() {
  if (currentPipVideo) {
    currentPipVideo.removeEventListener('play', startDrawingFrames);
    currentPipVideo.removeEventListener('pause', stopDrawingFrames);
    currentPipVideo.removeEventListener('ended', stopDrawingFrames);
    currentPipVideo.removeAttribute('__pip__');
    currentPipVideo = null;
  }
  if (pipCanvas) {
    stopDrawingFrames();
    pipCanvas.removeAttribute('__pip__');
    document.body.removeChild(pipCanvas);
    pipCanvas = null;
  }
}

// 保留原逻辑,仅替换触发的requestPictureInPicture函数
function maybeUpdatePictureInPictureVideo(entries, observer) {
  const observedVideo = entries[0].target;
  if (!document.querySelector('[__pip__]')) {
    observer.unobserve(observedVideo);
    return;
  }
  const video = findLargestPlayingVideo();
  if (video && !video.hasAttribute('__pip__')) {
    observer.unobserve(observedVideo);
    requestPictureInPicture(video);
  }
}

关键逻辑说明

  • Canvas中转:Chrome允许Canvas元素进入PIP模式,且Canvas的尺寸可以完全自定义,不受原视频宽高比约束。
  • 帧绘制:通过setInterval定时将视频帧绘制到Canvas,用drawImage的拉伸模式填充整个Canvas,实现任意比例显示。
  • 资源清理:退出PIP时必须清理定时器、事件监听和DOM元素,避免内存泄漏。
  • 原逻辑兼容:保留maybeUpdatePictureInPictureVideo的原有逻辑,确保扩展自动切换视频的功能正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 01:55:18