Unity中用UDesktopDuplication向Agora推送视频帧遇灰屏问题求助
Agora Windows屏幕共享灰屏问题排查与解决
你遇到的灰屏问题,核心原因大概率是BGRA转RGBA的格式转换没真正生效,再加上可能的纹理数据读取、参数配置问题,导致Agora无法正确解析视频帧。下面是具体排查点和解决办法:
一、格式转换的核心问题
你只是修改了externalVideoFrame.format为RGBA,但实际传入的_shareData还是BGRA格式的字节数据,Agora收到后按RGBA解析自然会显示异常。必须手动交换每个像素的B和R通道:
// 在获取nativeByteArray之后,添加BGRA转RGBA的逻辑 for (int i = 0; i < nativeByteArray.Length; i += 4) { // 交换B和R通道:BGRA -> RGBA byte temp = nativeByteArray[i]; nativeByteArray[i] = nativeByteArray[i + 2]; nativeByteArray[i + 2] = temp; } nativeByteArray.CopyTo(_shareData);
二、纹理数据的有效性检查
UDesktopDuplication插件返回的texture可能未就绪,或者格式不是预期的BGRA32,先加日志确认:
Debug.Log("UDD Texture Format: " + _texture.format); // 确保纹理格式是BGRA32,否则转换逻辑不生效 if (_texture.format != TextureFormat.BGRA32) { Debug.LogError("Unsupported texture format, expected BGRA32"); yield break; }
三、Stride参数的正确设置
Stride(步长)应该是一行像素的总字节数,不是宽度。对于BGRA/RGBA格式,Stride = 宽度 × 4:
externalVideoFrame.stride = _texture.width * 4;
之前直接用_texture.width会导致Agora读取数据时错位,也是灰屏的常见原因。
四、时间戳与旋转参数的修正
- 时间戳建议用Unity的
Time.realtimeSinceStartup,避免DateTime.Now.Ticks的精度问题:externalVideoFrame.timestamp = (long)(Time.realtimeSinceStartup * 1000000); // 微秒级 - 旋转180度如果不是必要的,先注释掉,排除旋转导致的显示异常。
五、视频轨道的初始化验证
确保_videoTrack是正确创建的自定义采集轨道,初始化代码要类似:
_videoTrack = rtc.CreateCustomVideoTrack(true);
修改后的完整代码
private IEnumerator ShareScreen() { yield return new WaitForEndOfFrame(); IRtcEngine rtc = Agora.Rtc.RtcEngine.Instance; if (rtc == null) yield break; #if UNITY_EDITOR_OSX _texture.ReadPixels(_rect, 0, 0); _texture.Apply(); #else // 从UDD插件获取纹理 _texture = Manager.GetMonitor(displayIndex).texture; #endif // 检查纹理有效性和格式 if (_texture == null) { Debug.LogError("UDD returned null texture"); yield break; } Debug.Log("UDD Texture Format: " + _texture.format); if (_texture.format != TextureFormat.BGRA32) { Debug.LogError("Unsupported texture format, expected BGRA32"); yield break; } #if UNITY_2018_1_OR_NEWER NativeArray<byte> nativeByteArray = _texture.GetRawTextureData<byte>(); if (_shareData == null || _shareData.Length != nativeByteArray.Length) { _shareData = new byte[nativeByteArray.Length]; } // BGRA转RGBA:交换B和R通道 for (int i = 0; i < nativeByteArray.Length; i += 4) { byte temp = nativeByteArray[i]; nativeByteArray[i] = nativeByteArray[i + 2]; nativeByteArray[i + 2] = temp; } nativeByteArray.CopyTo(_shareData); #else _shareData = _texture.GetRawTextureData(); // 旧版本Unity需要手动处理转换,逻辑同上 #endif ExternalVideoFrame externalVideoFrame = new ExternalVideoFrame(); externalVideoFrame.type = VIDEO_BUFFER_TYPE.VIDEO_BUFFER_RAW_DATA; externalVideoFrame.format = VIDEO_PIXEL_FORMAT.VIDEO_PIXEL_RGBA; // 现在格式匹配了 externalVideoFrame.buffer = _shareData; #if UNITY_EDITOR_OSX externalVideoFrame.stride = (int)_rect.width * 4; externalVideoFrame.height = (int)_rect.height; #else externalVideoFrame.stride = _texture.width * 4; externalVideoFrame.height = _texture.height; #endif // 先注释裁剪,排除裁剪导致的问题 // externalVideoFrame.cropLeft = 10; // externalVideoFrame.cropTop = 10; // externalVideoFrame.cropRight = 10; // externalVideoFrame.cropBottom = 10; // externalVideoFrame.rotation = 180; // 先禁用旋转 externalVideoFrame.timestamp = (long)(Time.realtimeSinceStartup * 1000000); // 微秒级时间戳 var ret = rtc.PushVideoFrame(externalVideoFrame, _videoTrack); if (pushVideoFrame_Result != ret) { pushVideoFrame_Result = ret; Debug.Log($"PushVideoFrame ret = {pushVideoFrame_Result} time: {System.DateTime.Now.Millisecond}"); } }
额外排查点
- 检查
PushVideoFrame的返回值,如果不是0(成功),对照Agora错误码文档排查具体问题; - 确保UDD插件的权限正常,Windows下需要屏幕录制权限;
- 在Web端测试时,用Agora官方的Web Demo验证,排除Web端自身的问题。
内容的提问来源于stack exchange,提问作者Haither80
相关产品推荐
相关产品推荐

