如何水平翻转画中画(Picture-in-Picture)模式下的摄像头视频
解决画中画模式下摄像头视频镜像翻转失效的问题
问题根源
画中画(PiP)窗口的视频内容由浏览器独立渲染,不属于网页DOM树的一部分——网页里的CSS变换(包括:picture-in-picture伪类样式)无法作用到PiP窗口内的画面。仅靠CSS只能处理网页内的video元素显示,没法影响PiP模式的内容。
可行解决方案
方案1:直接配置MediaStreamTrack翻转流(简洁高效)
部分现代浏览器支持通过视频轨道的约束直接设置镜像翻转,这样网页和PiP模式的画面都会是翻转后的状态:
修改JS代码如下:
const button = document.getElementById('button'); const webCamVideo = document.querySelector('.webcam-vid') button.addEventListener('click', async () => { // 初始化摄像头流时尝试配置翻转 const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'user', transform: { horizontalFlip: true } } }); // 兼容不支持transform约束的浏览器,手动更新轨道配置 const videoTrack = stream.getVideoTracks()[0]; const capabilities = videoTrack.getCapabilities(); if (capabilities.transform?.horizontalFlip && !videoTrack.getConstraints().transform) { await videoTrack.applyConstraints({ transform: { horizontalFlip: true } }); } webCamVideo.srcObject = stream; // 修正原代码变量名错误:video改为webCamVideo webCamVideo.play(); webCamVideo.addEventListener('loadedmetadata', () => { webCamVideo.requestPictureInPicture() .catch(console.error) }); });
同时移除CSS中.webcam-vid的transform: scaleX(-1),因为流本身已经是翻转后的状态。
方案2:Canvas中转视频流(兼容性拉满)
如果需要适配不支持轨道transform约束的浏览器,用Canvas中转处理是通用方案:
- 在HTML中添加隐藏的Canvas元素:
<canvas id="mirrorCanvas" style="display: none;"></canvas> <video class="webcam-vid" autoPlay playsInline></video> <button class="btn btn-primary" id="button">Display Webcam feed in Picture-in-Picture mode</button>
- 修改JS代码,通过Canvas绘制翻转后的视频帧,再将Canvas的流作为video的源:
const button = document.getElementById('button'); const webCamVideo = document.querySelector('.webcam-vid'); const mirrorCanvas = document.getElementById('mirrorCanvas'); const ctx = mirrorCanvas.getContext('2d'); button.addEventListener('click', async () => { const stream = await navigator.mediaDevices.getUserMedia({ video: true }); webCamVideo.srcObject = stream; webCamVideo.addEventListener('loadedmetadata', () => { // 同步Canvas与视频的尺寸 mirrorCanvas.width = webCamVideo.videoWidth; mirrorCanvas.height = webCamVideo.videoHeight; // 循环绘制翻转后的视频帧 function drawMirrorFrame() { ctx.save(); ctx.scale(-1, 1); // 水平翻转画布上下文 ctx.drawImage(webCamVideo, -mirrorCanvas.width, 0, mirrorCanvas.width, mirrorCanvas.height); ctx.restore(); requestAnimationFrame(drawMirrorFrame); } drawMirrorFrame(); // 将Canvas的流作为video的源,PiP会使用Canvas的内容 const canvasStream = mirrorCanvas.captureStream(); webCamVideo.srcObject = canvasStream; webCamVideo.play(); webCamVideo.requestPictureInPicture().catch(console.error); }); });
同样移除CSS中的transform: scaleX(-1),因为Canvas已经完成了翻转处理。
额外提示
原代码存在变量名错误:video.play()需改为webCamVideo.play(),否则会触发未定义变量的报错。
内容的提问来源于stack exchange,提问作者Zaid
相关产品推荐
相关产品推荐

