1、使用XComponent组件显示相机的预览输出流时,如何获取相机的帧数据
A:通过创建双路预览来实现。
-
Xcomponent来创建预览流。
-
使用imageReceiver来监听图像信息。
2、如何获取前置摄像头的预览图像
A:示例代码如下
import { BusinessError } from '@kit.BasicServicesKit'; import { camera } from '@kit.CameraKit'; import { common } from '@kit.AbilityKit'; const context = getContext(this) as common.UIAbilityContext; @Entry @Component struct GetFrontCameraImage { private xComponentController: XComponentController = new XComponentController(); async getCameraImage() { // 1、使用系统相机框架camera模块获取物理摄像头信息。 let cameraManager = camera.getCameraManager(context); let camerasInfo: Array<camera.CameraDevice> = cameraManager.getSupportedCameras(); let cameraDevice: camera.CameraDevice = camerasInfo[0]; // 检测相机状态 cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => { console.log(`camera : ${cameraStatusInfo.camera.cameraId}`); console.log(`status : : ${cameraStatusInfo.status}`); }); // 2、创建并启动物理摄像头输入流通道 // 设置为前置摄像头 camera.CameraPosition.CAMERA_POSITION_FRONT let cameraInput = cameraManager.createCameraInput(camera.CameraPosition.CAMERA_POSITION_FRONT, camera.CameraType.CAMERA_TYPE_DEFAULT); await cameraInput.open(); // 3、拿到物理摄像头信息查询摄像头支持预览流支持的输出格式,结合XComponent提供的surfaceId创建预览输出通道 let outputCapability = cameraManager.getSupportedOutputCapability(cameraDevice, camera.SceneMode.NORMAL_PHOTO); let previewProfile = outputCapability.previewProfiles[0]; let surfaceId = this.xComponentController.getXComponentSurfaceId(); let previewOutput = cameraManager.createPreviewOutput(previewProfile, surfaceId); // 4、创建相机会话,在会话中添加摄像头输入流和预览输出流,然后启动会话,预览画面就会在XComponent组件上送显。 let captureSession = cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO); captureSession.beginConfig(); captureSession.addInput(cameraInput); captureSession.addOutput(previewOutput); captureSession.commitConfig() captureSession.start(); } build() { Row() { Column({ space: 20 }) { XComponent({ id: 'xComponentId1', type: 'surface', controller: this.xComponentController }) .height(300) Button('打开摄像头') .onClick(() => { // 在调用前确保已经获得相机权限 this.getCameraImage(); }) } .width('100%') } .height('100%') } }
3、如何设置相机焦距
A:步骤如下
-
判断当前摄像头是否为前置摄像头,前置摄像头不支持设置焦距。
-
通过getZoomRatioRange()接口获取设备焦距设置支持的最大、最小范围。
-
判断目标焦距参数大小是否在步骤二获取的范围内,然后通过setZoomRatio()接口设置相机焦距。
4、如何检测当前相机服务的状态
A:通过cameraManager设置状态回调返回相机状态。
import { camera } from '@kit.CameraKit'; import { BusinessError } from '@kit.BasicServicesKit'; let cameraManager = camera.getCameraManager(getContext(this)); cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => { console.log(`camera : ${cameraStatusInfo.camera.cameraId}`); console.log(`status: ${cameraStatusInfo.status}`); });
相机状态:CameraStatus
枚举,相机状态。
CAMERA_STATUS_APPEAR 0 新的相机出现。
CAMERA_STATUS_DISAPPEAR 1 相机被移除。
CAMERA_STATUS_AVAILABLE 2 相机可用。
CAMERA_STATUS_UNAVAILABLE 3 相机不可用。
5、相机是否支持HDR模式的采集
A:支持HDR模式,采用的是HDR vivid标准。
6、如何读取相机的预览图
A:开发步骤如下:
-
导入image接口。
创建双路预览流的SurfaceId,除XComponent组件的SurfaceId外,还需要使用ImageReceiver组件创建生成的SurfaceId,需要使用image模块提供的接口。
-
创建ImageReceiver组件Surface。
-
创建XComponent组件Surface。
-
实现双路预览。
-
通过ImageReceiver实时获取预览图像。
7、如何保证相机在全屏预览时不变形
A:需要获取手机的宽高比,用手机的屏幕的height/width去和支持的预览尺寸的width/height去取最贴近的值。预览流与录像输出流的分辨率的宽高比要保持一致,如示例代码中宽高比为1920:1080 = 16:9,则需要预览流中的分辨率的宽高比也为16:9,如分辨率选择640:360,或960:540,或1920:1080,以此类推。
8、相机预览切后台再回来画面不正确
A:切换后台再切回来,必须要重新初始化相机才可以。因为切后台,相机资源是全部回收的。
9、如何实现相机关闭
A:实现相机关闭参考代码如下:
// 停止当前会话 photoSession.stop(); // 释放相机输入流 cameraInput.close(); // 释放预览输出流 previewOutput.release(); // 释放拍照输出流 photoOutput.release(); // 释放会话 photoSession.release(); // 会话置空 photoSession = undefined;
10、预览流黑屏但无报错信息该怎么解决
A:未正确获取相机权限,就进行初始化相机、获取相机输入流等操作。应用切换至后台后切回,相机资源被回收后,没有重新获取权限开启预览导致。设置的预览流尺寸不支持。
-
确保初始化相机、获取相机输入流等操作之前先正确获取相机权限。
-
因为当应用被切换到后台后,相机资源会被全部回收,所以为了避免出现前后台切换后预览流黑屏的问题,需在onPageShow中进行重新创建会话、配置会话、启动等操作,并在onPageHide中对相机资源进行销毁。
-
可先获取相机设备支持的输出流能力,得到支持的预览尺寸。
11、调用API方法camera.getCameraManager传入context报错如何解决
A:该问题是由不兼容修改引起的。之前用的是FA模型的context,现在应用都是Stage模型的,所以有app/Context和application/Context的变化,可使用getContext() as common.BaseContext获取需要的context。
12、如何避免预览流产生畸变
A:使用下列代码获取设备支持的宽和高,然后根据手机屏幕的宽高设置最合适的预览流分辨率,并且使得surface和XComponent的宽高相同。
//预览流与录像输出流的分辨率的宽高比要保持一致 let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles; let position: number = 0; if (previewProfilesArray != null) { previewProfilesArray.forEach((value: camera.Profile, index: number) => { // 查看支持的预览尺寸 console.info(TAG, `支持的预览尺寸: [${value.size.width},${value.size.height},${value.size.width / value.size.height}]`); if (value.size.width === 2592 && value.size.height === 1200) { position = index; } }) } else { console.error(TAG, "createOutput photoProfilesArray == null || undefined"); } // DocsCode 2 let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles; if (!photoProfilesArray) { console.error(TAG, "createOutput photoProfilesArray == null || undefined"); } this.xComponentWidth = previewProfilesArray[position].size.width; this.xComponentHeight = previewProfilesArray[position].size.height; this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: this.xComponentWidth, surfaceHeight: this.xComponentHeight }); // 创建预览输出流,其中参数 surfaceId 参考上文 XComponent 组件,预览流为XComponent组件提供的surface try { previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[position], surfaceId); } catch (error) { let err = error as BusinessError; console.error(TAG, `Failed to create the PreviewOutput instance. error code: ${err.code}`); } if (previewOutput === undefined) { return; } // 监听预览输出错误信息 previewOutput.on('error', (error: BusinessError) => { console.error(TAG, `Preview output error code: ${error.code}`); }); // 创建ImageReceiver对象,并设置照片参数:分辨率大小是根据前面 photoProfilesArray 获取的当前设备所支持的拍照分辨率大小去设置 let size: image.Size = { height: 1200, width: 2592 } let imageReceiver: image.ImageReceiver = image.createImageReceiver(size, 4, 8);
13、如何开关闪光灯
A:使用isFlashModeSupported方法检测设备是否支持需要设置的闪光灯模式后,使用setFlashMode设置闪光灯模式。
14、如何调用系统拍照并获取图片
A:可参考如下代码,拉起系统拍照页面并获取图片uri:
@State imagePathSrc: String = ''; context:common.UIAbilityContext | undefined = (getContext(this) as common.UIAbilityContext); savePath: string = getContext().filesDir; async thirdPartyCall(supportMultiMode: boolean): Promise<common.AbilityResult | undefined> { console.log("thirdPartyCall savaPath=" + this.savePath) // ohos.want.action.imageCapture // 拉起拍照功能 let want: Want = { "action": 'ohos.want.action.imageCapture', "parameters": { supportMultiMode: supportMultiMode, callBundleName: "com.example.systemcapturegetphoto" } }; // 获取图片uri if (this.context) { let result: common.AbilityResult = await this.context.startAbilityForResult(want); let params = result?.want?.parameters as Record<string, string | number> this.imagePathSrc = params?.resourceUri as string; console.info('Operation imagePathSrc= ' + this.imagePathSrc); } return undefined; }
15、视频的SPS/PPS需要单独传递给解码器吗
A:AVC视频中的SPS/PPS需要通过queueInputBuffer提交。
16、视频流支持哪些格式
A:ts层无其他格式, 这些字节数据可以转成pixelMap,经过编码后可以转成JPEG、WebP 和 png 格式(目前支持这三种)。
17、视频预览分辨率设置
问题现象
旋转手机,预览画面中同一个物品高度会发生明显变化,画面畸变。代码中的预览分辨率:previewProfile {"format":1003,"size":{"width":3200,"height":2400}},XComponent的surfaceWidth: 3200, surfaceHeight: 2400。
XComponent({ id: 'componentId', type: 'surface', controller: this.mXComponentController, }).onLoad(async () => { this.surfaceId = this.mXComponentController.getXComponentSurfaceId(); let baseContext = getContext() as common.BaseContext; await this.initCamera(baseContext, this.surfaceId) }).width('100%') .height('100%')
A:上面代码 .width('100%').height('100%') 这两个值不要都设置成100%, 保证width和height的比例与previewProfile的height与width比例一致。
18、如何连续获取相机预览流数据
A:使用双路预览获取连续数据,设置previewOutput2接收连续数据。
20、如何获取相机原始yuv数据流
A:初始化相机类,传入xcomponent组件的id作为参数,使用双路预览绑定ImageReceiver接收相机原始数据流并保存为yuv形式,实例代码链接:文档中心
21、如何调用相机开放的接口,拍照并获取拍照的图片uri
A:
-
在模块级module.json5中申明权限
-
获取权限
-
创建拍摄和预览页面
-
创建camera类完成相机初始化、拍摄和获取图片uri并存储
22、YUV数据相关格式
A:目前相机给出的YUV数据是8bit位深的,采用的是BT709色域。
相机有HDR模式,采用的是HDR vivid标准;返回10bit位深的YUV数据,使用的是BT2020色域。
更多详情及参考代码查看如下:文档中心