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

立体并排视频黑白效果闪烁问题排查求助

问题原因分析

你遇到的画面频繁切换问题,核心根源是两个按钮的点击事件各自启动了独立的无限递归setTimeout循环:

  • 点击「正常」按钮时,myFunction会持续循环调用自己,不断把原始视频帧绘制到canvas上
  • 点击「黑白」按钮时,myFunction1也会启动自己的无限循环,持续处理黑白帧并覆盖到canvas上
  • 这两个循环会同时运行、交替修改canvas内容,最终导致画面在正常与黑白状态之间频繁跳变

另外代码里还有个小拼写错误:back.hight=ch应该是back.height=ch,不过这不是导致切换问题的直接原因。

修复方案

我们需要把逻辑改成单一动画循环+模式状态管理的方式:只维护一个全局渲染循环,通过变量记录当前要使用的效果模式,每次循环根据模式处理画面,避免多个循环互相干扰。

修改后的完整代码如下:

<!DOCTYPE html> 
<meta charset=utf-8 /> 
<script src="video.js" type="text/javascript"></script> 
<link href="video-js.css" rel="stylesheet" type="text/css"> 
<title>Mon projet </title> 
<h1> <marquee>Streaming </marquee></h1> 
<center> 
<h1> Choisir effet </h1> 
<span id="cvsModeLbl">Mode:</span> 
<input type="button" id="cvsbtnNormal" value="Normal" /> 
<input type="button" id="cvsbtnBW" value="Black &amp; White" /> 
<h1> Vidéo Side by side</h1> 
<video id=v controls loop width="500" height="400"> 
<source src=video2.mp4 type=video/mp4> 
<source src=video2.webm type=video/webm> 
<source src=video2.ogg type=video/ogg> 
</video> 
<canvas id=c width="500" height= "400"></canvas> 
<style> canvas { background: black; } </style> 
<script> 
var v = document.getElementById('v'); 
var canvas = document.getElementById('c'); 
var context = canvas.getContext('2d'); 
var back = document.createElement('canvas'); 
var backcontext = back.getContext('2d'); 
var back1 = document.createElement('canvas'); 
var backcontext1 = back1.getContext('2d'); 
v.crossOrigin = 'anonymous'; 
var cw,ch; 
cw = v.width; 
ch = v.height; 
back.width = cw; 
back.height = ch; // 修复拼写错误:hight -> height
back1.width = cw; 
back1.height = ch; 

// 新增全局变量:记录当前选中的效果模式
var currentEffect = 'normal';

var effectNormal = document.getElementById("cvsbtnNormal"); 
var effectBw = document.getElementById("cvsbtnBW"); 

// 按钮点击仅修改模式,不启动新循环
effectNormal.addEventListener("click", function() {
  currentEffect = 'normal';
}); 
effectBw.addEventListener("click", function() {
  currentEffect = 'bw';
}); 

// 单一渲染循环:根据当前模式处理画面
function renderFrame() {
  context.clearRect(0, 0, cw, ch);
  
  if (currentEffect === 'normal') {
    // 正常模式:直接绘制原始视频帧
    context.drawImage(v, 0, 0, cw, ch);
  } else if (currentEffect === 'bw') {
    // 黑白模式:先绘制原始帧,再处理灰度效果
    context.drawImage(v, 0, 0, cw, ch);
    var idata = context.getImageData(0, 0, cw, ch);
    var data = idata.data;
    for(var i = 0; i < data.length; i+=4) {
      var r = data[i], g = data[i+1], b = data[i+2];
      // 使用更符合人眼视觉的灰度计算公式
      var gray = r * 0.299 + g * 0.587 + b * 0.114;
      data[i] = gray;
      data[i+1] = gray;
      data[i+2] = gray;
    }
    context.putImageData(idata, 0, 0);
  }
  
  // 用requestAnimationFrame替代setTimeout,动画更流畅、性能更优
  requestAnimationFrame(renderFrame);
}

// 启动渲染循环
renderFrame();
</script>
关键改进点说明
  • 单一渲染循环:使用requestAnimationFrame替代setTimeout,它是浏览器专门为动画优化的API,能和屏幕刷新率同步,动画更流畅且性能更稳定
  • 模式状态管理:通过currentEffect变量统一控制当前渲染效果,按钮点击仅修改这个变量,不会启动多个冲突的循环
  • 修复拼写错误:修正了back.hight的拼写问题
  • 优化灰度计算:使用符合人眼视觉感受的灰度公式(0.299R + 0.587G + 0.114B),比简单的(r+g+b)/3效果更自然

修改后点击按钮切换效果时,画面会稳定显示对应模式,不会再出现频繁跳变的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:00:31