【代码案例】HarmonyOS鸿蒙Next 解决相机预览花屏案例

发布于 1周前 作者 ionicwang 来自 鸿蒙OS

【代码案例】HarmonyOS鸿蒙Next 解决相机预览花屏案例

HarmonyOS Next应用开发案例(持续更新中……)

本案例完整代码,请访问:https://gitee.com/harmonyos-cases/cases/tree/master/CommonAppDevelopment/feature/dealstridesolution

介绍

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

效果图预览

![使用说明]

  • 本案例仅支持真机验证,因在案例集合中导致权限弹窗reason只支持一种string。
  • 点击进入案例,授权给相机。
  • 三个方案滑动页面不会出现花屏。
  • 点击相机右上角方案说明,可出现相关方案的具体描述。

实现思路

本例涉及的关键特性和实现方案如下:

方案一

  1. 应用通过image.ImageReceiver注册imageArrival图像回调方法,获取每帧图像数据实例image.Image,应用通过定义一个width为1920*height为1080分辨率的预览流直接创建pixelMap,此时获取到的stride的值为1920。源码参考CameraServiceCrop.ets

  2. 在初始相机模块时,调用onImageArrival(),将未处理的width和height作为size,创建PixelMap,通过在Image中传入被@StorageLink修饰的变量stridePixel进行数据刷新,图片送显。源码参考ImageViewCrop.ets

  3. 当stride和width相等时,按宽读取buffer不影响结果。 当stride和width不等时,如果应用想使用byteBuffer预览流数据创建pixelMap直接显示,可以根据stride*height字节的大小先创建pixelMap,然后调用PixelMap的cropSync方法裁剪掉多余的像素,从而正确处理stride,解决预览流花屏问题。源码参考CameraServiceCrop.ets

方案二

  1. 方案二的创建pixelMap、图片送显和方案一的1、2步骤一样,此处不再赘述。

当stride和width相等时,按宽读取buffer不影响结果。 当stride和width不等时,将相机返回的预览流数据即component.byteBuffer的数据去除stride,拷贝得到新的dstArr数据进行数据处理,将处理后的dstArr数组buffer,通过width和height直接创建pixelMap, 并存储到全局变量stridePixel中,传给Image送显,解决预览流花屏问题。源码参考CameraServiceUint.ets

方案三

  1. 使用XComponent渲染预览对象输出的图像,源码参考XComponentView.ets

  2. 在初始相机模块时,使用getXComponentSurfaceId获取XComponent对应Surface的ID,调用createPreviewOutput创建预览输出对象,图片送显,源码参考CameraService.ets

注意

本示例未设置成全屏状态,开发者可通过设置宽或高为100%,再根据当前设备的像素比设置aspectRatio(宽/高),例如Mate60可设置为aspectRatio(9/16)。

工程结构&模块类型

dealstridesolution                           // har类型
|--components
|   |--ImageViewCrop.ets                    // 组件层-使用cropSync方法裁剪掉多余的像素处理图像组件
|   |--ImageViewUint.ets                    // 组件层-使用新建的width和height直接创建pixelMap处理图像组件
|   |--MainPage.ets                         // 组件层-tab主页面
|   |--XComponentView.ets                   // 组件层-使用createPreviewOutput创建预览输出对象直接输出图像组件
|--model 
|   |--CameraService.ets                    // 模型层-使用createPreviewOutput创建预览输出对象直接输出图像
|   |--CameraServiceCrop.ets                // 模型层-使用cropSync方法裁剪掉多余的像素处理图像
|   |--CameraServiceUint.ets                // 模型层-使用新建的width和height直接创建pixelMap处理图像
|--common 
|   |--Constants.ets                        // 公共层-相关方案解释信息
|   |--Logger.ets                           // 公共层-日志

模块依赖

参考资料


更多关于【代码案例】HarmonyOS鸿蒙Next 解决相机预览花屏案例的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS鸿蒙Next中,相机预览花屏问题通常与图像缓冲区处理或渲染流程有关。以下是一个简化的代码案例,展示了如何通过调整图像缓冲区管理和渲染逻辑来解决花屏问题。

import camera from '@ohos.camera';
import image from '@ohos.image';
import display from '@ohos.display';

// 初始化相机
let cameraManager = camera.getCameraManager();
let cameraDevices = cameraManager.getSupportedCameras();
let cameraInput = cameraManager.getCameraInput(cameraDevices[0]);

// 创建图像接收器
let imageReceiver = image.createImageReceiver(1920, 1080, image.ImageFormat.JPEG, 3);

// 设置相机预览输出
let previewOutput = camera.createPreviewOutput(imageReceiver.getSurface());
cameraInput.addOutput(previewOutput);

// 启动相机
cameraInput.start();

// 渲染图像
let displayManager = display.getDisplayManager();
let displayInstance = displayManager.getDefaultDisplay();
let displaySurface = displayInstance.createSurface();
displaySurface.setSurfaceSize(1920, 1080);

imageReceiver.on('imageAvailable', (image) => {
    let imageBuffer = image.getBuffer();
    displaySurface.drawBuffer(imageBuffer);
});

// 停止相机
cameraInput.stop();

在这个案例中,我们通过创建ImageReceiver来接收相机预览的图像数据,并通过DisplaySurface将图像渲染到屏幕上。通过这种方式,可以避免因图像缓冲区处理不当而导致的预览花屏问题。

更多关于【代码案例】HarmonyOS鸿蒙Next 解决相机预览花屏案例的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,相机预览花屏问题通常是由于相机缓冲区未正确处理或渲染管线配置不当导致的。以下是一个简单的解决方案代码示例:

// 初始化相机
Camera camera = Camera.open();

// 设置相机参数
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(width, height); // 设置预览尺寸
camera.setParameters(parameters);

// 设置预览Surface
camera.setPreviewSurface(surface);

// 启动预览
camera.startPreview();

// 处理缓冲区
camera.setPreviewCallback(new Camera.PreviewCallback() {
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        // 处理每一帧数据,确保缓冲区正确渲染
        // 可以在这里进行图像处理或直接渲染
    }
});

关键点:

  1. 设置正确的预览尺寸:确保预览尺寸与设备屏幕分辨率匹配。
  2. 正确处理缓冲区:通过onPreviewFrame回调处理每一帧数据,避免缓冲区未正确处理导致花屏。
  3. 释放资源:在Activity或Fragment的onPauseonDestroy中释放相机资源,防止内存泄漏。

通过以上步骤,可以有效解决HarmonyOS鸿蒙Next中相机预览花屏的问题。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!