Unity WebGL下VideoPlayer更新Slider进度导致视频播放阻塞
Unity WebGL VideoPlayer更新进度条导致视频仅显示首帧故障修复
问题表现
- 运行平台:Unity WebGL
- 故障现象:点击播放按钮后视频仅渲染第一帧就停止,注释掉Update生命周期中给进度Slider赋值的代码行后,视频可正常播放
- 定位到的问题代码段:
if (video.isPlaying) { if (!video.isPrepared) return; videoSlider.value = (float)NTime; // 触发故障的代码行 }
- 关联的进度计算逻辑:
// NTime依赖Duration计算 public ulong Duration { get { return (ulong)(video.frameCount / video.frameRate); } } public double NTime { get { return VideoTime / Duration; } }
故障根因
两个问题叠加导致故障,在WebGL平台下100%触发:
- Slider事件循环触发Seek:进度条Slider的
onValueChanged事件已绑定SeekSlider跳转方法,代码主动修改videoSlider.value时会直接触发该事件,每帧执行一次视频进度跳转,把视频进度拉回计算值,导致播放头无法正常前进。 - 除零错误生成无效值:WebGL平台视频解码依赖浏览器原生能力,
isPrepared返回true的初始几帧内,video.frameCount尚未拿到有效解码数据,返回值为0,直接导致Duration计算结果为0,NTime做除法时得到NaN/无穷大的无效值,触发Slider异常的同时,Seek方法会把视频进度重置到0点,最终只渲染第一帧。
修复方案
按以下步骤修改代码即可:
- 先在SliderVideo类中添加状态锁字段,避免代码更新Slider时误触发进度跳转:
// 加在类的字段定义区域 private bool isUpdatingSlider = false;
- 修改
SeekSlider方法,开头增加锁判断:
public void SeekSlider() { // 代码主动更新Slider时不触发跳转 if (isUpdatingSlider) return; video.time = (videoSlider.value * Duration); }
- 修复Duration属性的有效性校验,避免除零:
public ulong Duration { get { // 元数据无效时返回兜底值,避免除零 if (!video.isPrepared || video.frameCount <= 0 || video.frameRate <= 0) return 1; return (ulong)(video.frameCount / video.frameRate); } }
- 优化NTime属性,钳制取值范围在Slider合法区间内:
public double NTime { get { double duration = Duration; if (duration <= 0) return 0; double nTime = VideoTime / duration; // 进度值固定在0-1区间,避免超出Slider默认取值范围 return System.Math.Clamp(nTime, 0d, 1d); } }
- 修改Update中Slider赋值逻辑,加锁保护:
private void Update() { if (video.isPlaying) { if (!video.isPrepared) return; // 赋值前加锁 isUpdatingSlider = true; videoSlider.value = (float)NTime; // 赋值完成解锁 isUpdatingSlider = false; video.SetDirectAudioVolume(0, volumeSlider.value); } // 以下全屏逻辑保持原有代码不变 if (fullScreen) { if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0) { timerMouse = 0; buttons.gameObject.SetActive(true); } else { timerMouse += Time.deltaTime; if (timerMouse > 3) { timerMouse = 3; buttons.gameObject.SetActive(false); } } } }
注:该问题仅在WebGL平台高频触发是因为WebGL下VideoPlayer的元数据加载时序和Editor/Standalone平台存在差异,Editor等平台
isPrepared返回true时frameCount已拿到有效值,不会触发除零,但Slider事件循环触发Seek的隐患在所有平台都存在。
内容的提问来源于stack exchange,提问作者Raoul L'artiste
相关产品推荐
相关产品推荐

