介绍

开发者在使用相机服务时,如果仅用于预览流展示,通常使用XComponent组件实现,如果需要获取每帧图像做二次处理(例如获取每帧图像完成二维码识别或人脸识别场景),可以通过ImageReceiver中imageArrival事件监听预览流每帧数据,解析图像内容。在解析图像内容时,如果未考虑stride,直接通过使用width*height读取图像内容去解析图像,会导致相机预览异常,从而出现相机预览花屏的现象。
当开发者获取预览流每帧图像buffer后,若发现图片内容出现花屏堆叠状,出现“相机预览花屏”现象,此时需要排查解析每帧图像,当预览流图像stride与width不一致时,需要对stride进行无效像素处理。

解决方案

开发者使用width,height,stride三个值,处理相机预览流数据。
分两种情况:

  • 当stride和width相等时,按宽读取buffer不影响结果;
  • 当stride和width不等时,将相机返回的预览流数据即component.byteBuffer中的数据去除掉stride, 此时将component.byteBuffer中的数据去除掉stride,拷贝得到新的dstArr数据进行数据处理,将处理后的dstArr数组buffer,通过width和height直接创建pixelMap, 并存储到全局变量stridePixel中,传给Image送显。
    以下为关键示例代码:
function onImageArrival(receiver: image.ImageReceiver): void {
  receiver.on('imageArrival', () => {
    receiver.readNextImage((err: BusinessError, nextImage: image.Image) => {
      if (err || nextImage === undefined) {
        Logger.error(TAG, `requestPermissionsFromUser call Failed! error: ${err.code}`);
        return;
      }
      nextImage.getComponent(image.ComponentType.JPEG, async (err, component: image.Component) => {
        let width = 1080; 
        let height = 1080; 
        let stride = component.rowStride; 
        Logger.info(TAG, `receiver getComponent width:${width} height:${height} stride:${stride}`);

        if (stride === width) {
          let pixelMap = await image.createPixelMap(component.byteBuffer, {
            size: { height: height, width: width },
            srcPixelFormat: image.PixelMapFormat.NV21,
          })
          AppStorage.setOrCreate('stridePixel', pixelMap);
        } else {
          const dstBufferSize = width * height * 1.5; 
          const dstArr = new Uint8Array(dstBufferSize); 
          for (let j = 0; j < height * 1.5; j++) { 
            const srcBuf = new Uint8Array(component.byteBuffer, j * stride, width); 
            dstArr.set(srcBuf, j * width); // Store the width*height data in dstArr.
          }
          let pixelMap = await image.createPixelMap(dstArr.buffer, { 
            size: { height: height, width: width },
            srcPixelFormat: image.PixelMapFormat.NV21,
          })
          AppStorage.setOrCreate('stridePixel', pixelMap);
        }
        nextImage.release();
      })
    });
  })
}

 

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐