Hololens 2 WebRTC开启VideoStabilizationEnabled后ConvertToI420异常
HoloLens 2 WebRTC开启视频防抖后libyuv帧转换异常排查方案
问题根因
开启MRC视频防抖效果后,系统会自动对采集画面做边缘裁剪、对齐、缓冲处理,输出帧的实际分辨率、数据长度、像素格式不会和防抖关闭时的初始采集参数完全一致;原有代码直接复用初始化时缓存的固定分辨率、帧长度、格式参数传入libyuv::ConvertToI420,参数和实际帧数据不匹配,就会触发转换失败。
你遇到的帧长度异常可以直接验证:错误值497664恰好是768×432分辨率下NV12(YUV420)格式的标准帧长度(计算逻辑:768×432×3/2=497664),就是防抖自动裁剪边缘后输出了更低分辨率的帧,代码还按原896×504分辨率做参数校验和转换,必然出错。
排查解决步骤
- 每帧实时读取输出帧的真实属性,禁止复用初始化缓存的固定参数
防抖开启后帧属性可能动态变化,不要在采集初始化时读一次width/height/fourcc就全局复用,拿到每帧sample时直接从帧对象中读取实时参数:- 从帧对应的SoftwareBitmap对象读取真实PixelWidth、PixelHeight,不要用预设的896、504
- 直接从帧的PixelBuffer.Length属性读取真实帧长度,不要自己按预设分辨率计算
videoFrameLength - 校验当前帧的实际像素格式,确认映射到libyuv对应的FourCC枚举值,不要固定用初始化时记录的格式
- 调整MRC防抖配置,关闭自动缩放裁剪
你当前设置的15帧缓冲长度过大,HoloLens 2的MRC防抖会根据缓冲长度动态调整裁剪幅度,缓冲越大裁剪范围越大、输出分辨率缩水越明显,按如下方式修改配置:// 缓冲长度调整为3-5帧,平衡防抖效果和裁剪幅度 mrcVideoEffectDefinition.VideoStabilizationBufferLength(3); // 强制防抖输出和采集预设一致的NV12格式、896×504分辨率,禁止自动降分辨率 auto outputProps = Windows::Media::MediaProperties::VideoEncodingProperties::CreateUncompressed( Windows::Media::MediaProperties::MediaEncodingSubtypes::Nv12, 896, 504 ); mrcVideoEffectDefinition.OutputResolution(outputProps); - 修正
ConvertToI420传参逻辑
将原有传入固定缓存参数的逻辑替换为实时读取的帧参数,参考修改如下:// 从当前帧实时获取参数 auto currentBitmap = mediaFrame.VideoMediaFrame().SoftwareBitmap(); uint32_t actualWidth = currentBitmap.PixelWidth(); uint32_t actualHeight = currentBitmap.PixelHeight(); uint32_t actualFrameLen = currentBitmap.PixelBuffer().Length(); // 自行实现像素格式到libyuv FourCC的映射,NV12对应libyuv::FOURCC_NV12 uint32_t actualFourcc = ConvertBitmapFormatToFourCC(currentBitmap.BitmapPixelFormat()); const int conversionResult = libyuv::ConvertToI420( videoFrame, actualFrameLen, buffer.get()->MutableDataY(), buffer.get()->StrideY(), buffer.get()->MutableDataU(), buffer.get()->StrideU(), buffer.get()->MutableDataV(), buffer.get()->StrideV(), 0, 0, // 无裁剪 actualWidth, actualHeight, target_width, target_height, rotation_mode, actualFourcc); - 校验帧步长(stride)匹配
部分场景下防抖输出的帧会带内存对齐用的padding字节,行步长和width*像素字节数不一致,不要自行计算stride,直接从SoftwareBitmap的LockBuffer接口获取逐行真实步长传入libyuv,避免步长不匹配导致的花屏、崩溃问题。
内容的提问来源于stack exchange,提问作者davidlll
相关产品推荐
相关产品推荐

