HarmonyOS 鸿蒙Next中AVScreenCapture数据回调方法如何实现RGBA数据正常转换成YUV NV21格式?
HarmonyOS 鸿蒙Next中AVScreenCapture数据回调方法如何实现RGBA数据正常转换成YUV NV21格式?
使用AVScreenCapture实现录屏功能,我们业务需要获取音视频原始码流数据,获得原视频YUV NV21格式数据,但是目前回调接口只能获得RGBA数据,调用了多个第三方的转换方案,无法达到正常转换。都出现色彩异常和底部绿条纹,如下图。
手机系统 :5.1.0.150(SP7)
更多关于HarmonyOS 鸿蒙Next中AVScreenCapture数据回调方法如何实现RGBA数据正常转换成YUV NV21格式?的实战教程也可以访问 https://www.itying.com/category-93-b0.html
GetCapacity获取的是缓冲区的容量 不是buffer的大小 使用OH_AVBuffer_GetBufferAttr去获取缓冲区buffer的size
更多关于HarmonyOS 鸿蒙Next中AVScreenCapture数据回调方法如何实现RGBA数据正常转换成YUV NV21格式?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
最新的信息已在下方,
看一下函数ConvertRGBA8888ToNV21中的stride是否传对,stride传参为 rgbaData除以height的大小试试,
修改参数后的效果已在最新的回复中,并没有解决问题,
目前修改完参数之后如图:
OH_AVBuffer_GetCapacity和OH_AVCodecBufferAttr获取到的数据是一样的:
这里是config的相关数据:
这个是RGBA8888转NV21的方法:
stride如果给的是11008,图像出现斜条纹,如下图:
stride设置2720*4=10880的话就是原先最上方图像的效果
可以使用PixelMap原生转换
// 获取PixelMap对象后执行转换
const desiredPixelFormat: image.PixelMapFormat = image.PixelMapFormat.YUV_420_SP;
const buffer: ArrayBuffer = new ArrayBuffer(width * height * 3 / 2); // NV21数据长度
pixelMap.readPixelsToBuffer(buffer, {
desiredPixelFormat: desiredPixelFormat,
editable: true
});
底部绿条纹:检查UV分量计算是否溢出(值域应限制在0-255)
色彩偏差:确认是否错误使用BT.709矩阵(移动设备多用BT.601)
调试建议
通过hilog输出首尾像素值进行数据校验
console.info(`First YUV pixel: Y=${yuvBuffer}, U=${yuvBuffer[width*height+1]}`);
将生成的NV21数据写入文件后,使用FFplay播放验证
ffplay -video_size 640x480 -pixel_format nv21 -i output.yuv
-
YUV NV21格式特性
NV21属于YUV420SP格式,内存排列为:- 完整Y分量平面(width × height)
- UV分量交错排列(width × height / 2),其中V在前、U在后
-
典型错误原因
- 色彩异常:RGB到YUV的转换公式错误或未处理Alpha通道
- 底部绿条纹:UV分量内存未对齐或图像stride处理不当
目前发现问题所在:视频长2720,宽1260,正常RGBA8888数据应该是 2720 * 1260 * 4 = 13708800,回调给的数据 13873152。给的数据不是正常理论上的RGBA8888数据,所以调用第三方的进行转码就会有问题,不知道是什么原因。
转换的时候linesize有没有设置对?
在鸿蒙Next中,AVScreenCapture通过on(‘frameStart’)回调获取RGBA数据。使用GraphicsKit提供的YUV转换接口,调用image.Packing
或image.Conversion
相关方法进行格式转换。具体调用ImageConverter
组件的convertToYUV()
方法,指定输出格式为NV21。转换过程需注意RGBA数据的内存布局与YUV平面排列方式,确保色彩空间参数匹配。转换后的YUV数据可直接用于视频编码或传输。
在HarmonyOS Next中,AVScreenCapture回调返回的RGBA数据需要正确转换为YUV NV21格式。转换异常通常源于RGBA数据布局或转换算法的参数不匹配。以下是关键步骤:
-
确认RGBA数据格式:确保RGBA数据为每像素4字节(R、G、B、A),且排列顺序为RGBA(非ARGB)。若数据包含Alpha通道,需忽略或预乘处理。
-
实现转换算法:使用标准RGB到YUV NV21转换公式。注意NV21格式为YUV 4:2:0,其中Y平面完整,UV分量交错(V在前,U在后)。示例代码片段:
// 假设rgbaData为byte[],width和height为尺寸 int frameSize = width * height; byte[] yuvData = new byte[frameSize * 3 / 2]; // NV21大小 int r, g, b, y, u, v; int uvIndex = frameSize; int index = 0; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { r = rgbaData[index] & 0xFF; g = rgbaData[index + 1] & 0xFF; b = rgbaData[index + 2] & 0xFF; // 计算YUV y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16; u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128; v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128; yuvData[j * width + i] = (byte) Math.max(0, Math.min(255, y)); // NV21:UV分量在Y平面后,交替存储(VU交替) if (j % 2 == 0 && i % 2 == 0) { yuvData[uvIndex++] = (byte) Math.max(0, Math.min(255, v)); yuvData[uvIndex++] = (byte) Math.max(0, Math.min(255, u)); } index += 4; // 跳过RGBA的A通道 } }
-
处理色彩异常和绿条纹:
- 色彩异常:检查RGB到YUV的转换矩阵是否匹配设备色彩空间。部分设备可能使用BT.601或BT.709标准,需调整系数。
- 底部绿条纹:通常因数据对齐问题。确保转换时宽度为2的倍数(NV21要求UV分量宽度为2x2块),否则需填充数据。
-
性能优化:转换过程可并行化或使用Neon指令(ARM设备)加速。避免在回调中直接处理,建议移至后台线程。
若问题持续,验证输入RGBA数据是否完整,并检查回调中数据尺寸与声明的匹配性。