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

12 回复

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的大小试试,

修改参数后的效果已在最新的回复中,并没有解决问题,

目前修改完参数之后如图:

cke_133.png

OH_AVBuffer_GetCapacity和OH_AVCodecBufferAttr获取到的数据是一样的:

cke_186.png

这里是config的相关数据:

cke_1443.png

这个是RGBA8888转NV21的方法:

cke_2126.png

stride如果给的是11008,图像出现斜条纹,如下图:

cke_8298.png

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
  1. YUV NV21格式特性
    NV21属于YUV420SP格式,内存排列为:

    • 完整Y分量平面(width × height)
    • UV分量交错排列(width × height / 2),其中V在前、U在后
  2. 典型错误原因

    • 色彩异常:RGB到YUV的转换公式错误或未处理Alpha通道
    • 底部绿条纹:UV分量内存未对齐或图像stride处理不当

目前发现问题所在:视频长2720,宽1260,正常RGBA8888数据应该是 2720 * 1260 * 4 = 13708800,回调给的数据 13873152。给的数据不是正常理论上的RGBA8888数据,所以调用第三方的进行转码就会有问题,不知道是什么原因。

cke_2677.png

转换的时候linesize有没有设置对?

在鸿蒙Next中,AVScreenCapture通过on(‘frameStart’)回调获取RGBA数据。使用GraphicsKit提供的YUV转换接口,调用image.Packingimage.Conversion相关方法进行格式转换。具体调用ImageConverter组件的convertToYUV()方法,指定输出格式为NV21。转换过程需注意RGBA数据的内存布局与YUV平面排列方式,确保色彩空间参数匹配。转换后的YUV数据可直接用于视频编码或传输。

在HarmonyOS Next中,AVScreenCapture回调返回的RGBA数据需要正确转换为YUV NV21格式。转换异常通常源于RGBA数据布局或转换算法的参数不匹配。以下是关键步骤:

  1. 确认RGBA数据格式:确保RGBA数据为每像素4字节(R、G、B、A),且排列顺序为RGBA(非ARGB)。若数据包含Alpha通道,需忽略或预乘处理。

  2. 实现转换算法:使用标准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通道
        }
    }
    
  3. 处理色彩异常和绿条纹

    • 色彩异常:检查RGB到YUV的转换矩阵是否匹配设备色彩空间。部分设备可能使用BT.601或BT.709标准,需调整系数。
    • 底部绿条纹:通常因数据对齐问题。确保转换时宽度为2的倍数(NV21要求UV分量宽度为2x2块),否则需填充数据。
  4. 性能优化:转换过程可并行化或使用Neon指令(ARM设备)加速。避免在回调中直接处理,建议移至后台线程。

若问题持续,验证输入RGBA数据是否完整,并检查回调中数据尺寸与声明的匹配性。

回到顶部