Unity WebGL 播放 WebM 为何首帧显示黑屏?
数据小陈
结论
从描述看,黑帧更可能出现在 WebGL 的视频准备、解码或首帧输出阶段,原始 WebM 文件中未必有黑帧。Prepare() 是异步操作,调用后立刻执行 Play(),无法确保首帧已经解码并写入 Render Texture。固定等待 1 秒也不能可靠判断视频帧是否就绪,因为加载和解码时间会随浏览器、设备和网络状态变化。
等待准备完成和首帧就绪
先订阅事件,再调用 Prepare()。收到 prepareCompleted 后开始播放,收到首个 frameReady 后再显示 Quad。代码如下:
using UnityEngine;
using UnityEngine.Video;
public class WebGLVideoStartup : MonoBehaviour
{
[SerializeField] private VideoPlayer videoPlayer;
[SerializeField] private Renderer videoRenderer;
private bool firstFrameReady;
private void Start()
{
videoRenderer.enabled = false;
videoPlayer.sendFrameReadyEvents = true;
videoPlayer.prepareCompleted += OnPrepared;
videoPlayer.frameReady += OnFrameReady;
videoPlayer.Prepare();
}
private void OnPrepared(VideoPlayer source)
{
source.Play();
}
private void OnFrameReady(VideoPlayer source, long frameIndex)
{
if (firstFrameReady)
return;
firstFrameReady = true;
videoRenderer.enabled = true;
}
private void OnDestroy()
{
videoPlayer.prepareCompleted -= OnPrepared;
videoPlayer.frameReady -= OnFrameReady;
}
}
prepareCompleted 表示准备阶段结束,但不代表有效视频帧已经显示。因此,示例会等到 frameReady 才启用 Renderer。请确认所用 Unity 版本和 WebGL 目标浏览器支持并触发 frameReady。如果目标环境无法使用该事件,可以显示加载遮罩或占位画面,并根据目标平台上实际可观察到的就绪信号控制画面显示。
检查 Render Texture 和 Alpha
- 确认 VideoPlayer 的
targetTexture指向材质实际使用的纹理,并检查播放时纹理是否收到新帧。排查 Custom Render Texture 时,也要检查它的 OnDemand 更新设置。可以暂时换成普通 RenderTexture 对照,判断问题是否与纹理更新路径有关。 - 首帧就绪前隐藏 Quad 或显示占位画面,避免把 Render Texture 的初始内容当作视频帧显示。调整材质 Alpha 无法让尚未输出的视频帧变成有效画面。
- 暂时用不带 Alpha Channel 的 WebM 做对照。如果黑帧只出现在启用了 Alpha 的文件中,再检查目标浏览器对该 WebM 编码和透明通道的实际解码表现。支持情况可能因浏览器和运行环境而异。
- 在实际发布目标的浏览器中复测。Editor 中播放正常,不能证明 WebGL 浏览器的解码和纹理输出时序也相同。
当前代码需要调整的时序
原代码在调用 Prepare() 后立即执行 Play()。loopPointReached 则会在播放到循环末尾时触发,不适合判断首帧是否就绪。由准备完成和首帧到达的回调控制画面显示,比等待固定时长更可靠。
如果改用就绪事件控制显示后仍然看到黑帧,请进一步确认黑色来自视频实际首帧、透明区域的合成结果,还是目标纹理的初始内容,并记录目标浏览器、Unity 版本和 WebGL 构建设置,便于缩小排查范围。
备注:内容仅供参考。
