1# 双路预览 2 3相机应用通过控制相机,实现图像显示(预览)、照片保存(拍照)、视频录制(录像)等基础操作。相机开发模型为Surface模型,即应用通过Surface进行数据传递,通过ImageReceiver的surface获取拍照流的数据、通过XComponent的surface获取预览流的数据。 4 5如果要实现双路预览,即将拍照流改为预览流,将拍照流中的surface改为预览流的surface,通过ImageReceiver的surface创建previewOutput,其余流程与拍照流和预览流一致。 6 7详细的API说明请参考[Camera API参考](../reference/apis/js-apis-camera.md)。 8 9## 约束与限制 10 11- 暂不支持动态添加流,即不能在没有调用session.stop的情况下,调用addOutput添加流。 12- 对ImageReceiver组件获取到的图像数据处理后,需要将对应的图像Buffer释放,确保Surface的BufferQueue正常轮转。 13 14## 调用流程 15 16双路方案调用流程图建议如下: 17 18 19 20## 开发步骤 21 221. 导入image接口。 23 24 创建双路预览流的SurfaceId,除XComponent组件的SurfaceId外,还需要使用ImageReceiver组件创建生成的SurfaceId,需要使用image模块提供的接口。 25 26 ```ts 27 import image from '@ohos.multimedia.image'; 28 ``` 29 302. 创建ImageReceiver组件Surface。 31 32 ```ts 33 async function getImageReceiverSurfaceId(): Promise<string | undefined> { 34 let receiver: image.ImageReceiver = image.createImageReceiver(640, 480, 4, 8); 35 console.info('before ImageReceiver check'); 36 let ImageReceiverSurfaceId: string | undefined = undefined; 37 if (receiver !== undefined) { 38 console.info('ImageReceiver is ok'); 39 let ImageReceiverSurfaceId: string = await receiver.getReceivingSurfaceId(); 40 console.info(`ImageReceived id: ${ImageReceiverSurfaceId}`); 41 } else { 42 console.info('ImageReceiver is not ok'); 43 } 44 return ImageReceiverSurfaceId; 45 } 46 ``` 47 483. 创建XComponent组件Surface。 49 50 可参考[相机预览指导文档](camera-preview.md)。 51 52 ```ets 53 //xxx.ets 54 // 创建XComponentController 55 @Component 56 struct XComponentPage { 57 // 创建XComponentController 58 mXComponentController: XComponentController = new XComponentController; 59 60 build() { 61 Flex() { 62 // 创建XComponent 63 XComponent({ 64 id: '', 65 type: 'surface', 66 libraryname: '', 67 controller: this.mXComponentController 68 }) 69 .onLoad(() => { 70 // 设置Surface宽高(1920*1080),预览尺寸设置参考前面 previewProfilesArray 获取的当前设备所支持的预览分辨率大小去设置 71 this.mXComponentController.setXComponentSurfaceSize({surfaceWidth:1920,surfaceHeight:1080}); 72 // 获取Surface ID 73 let surfaceId: string = this.mXComponentController.getXComponentSurfaceId(); 74 }) 75 .width('1920px') 76 .height('1080px') 77 } 78 } 79 } 80 ``` 81 824. 实现双路预览。 83 84 将步骤2、3生成的两路SurfaceId通过createPreviewOutput方法传递到相机服务,创建两路预览流,其余流程按照正常预览流程开发。 85 86 ```ts 87 import camera from '@ohos.multimedia.camera'; 88 89 async function createDualChannelPreview(cameraManager: camera.CameraManager, XComponentSurfaceId: string, receiver: image.ImageReceiver): Promise<void> { 90 let camerasDevices: Array<camera.CameraDevice> = cameraManager.getSupportedCameras(); // 获取支持的相机设备对象 91 92 // 获取profile对象 93 let profiles: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(camerasDevices[0]); // 获取对应相机设备profiles 94 let previewProfiles: Array<camera.Profile> = profiles.previewProfiles; 95 96 // 预览流1 97 let previewProfilesObj: camera.Profile = previewProfiles[0]; 98 99 // 预览流2 100 let previewProfilesObj2: camera.Profile = previewProfiles[0]; 101 102 // 创建 预览流1 输出对象 103 let previewOutput: camera.PreviewOutput = cameraManager.createPreviewOutput(previewProfilesObj, XComponentSurfaceId); 104 105 // 创建 预览流2 输出对象 106 let imageReceiverSurfaceId: string = await receiver.getReceivingSurfaceId(); 107 let previewOutput2: camera.PreviewOutput = cameraManager.createPreviewOutput(previewProfilesObj2, imageReceiverSurfaceId); 108 109 // 创建cameraInput对象 110 let cameraInput: camera.CameraInput = cameraManager.createCameraInput(camerasDevices[0]); 111 112 // 打开相机 113 await cameraInput.open(); 114 115 // 会话流程 116 let captureSession: camera.CaptureSession = cameraManager.createCaptureSession(); 117 118 // 开始配置会话 119 captureSession.beginConfig(); 120 121 // 把CameraInput加入到会话 122 captureSession.addInput(cameraInput); 123 124 // 把 预览流1 加入到会话 125 captureSession.addOutput(previewOutput) 126 127 // 把 预览流2 加入到会话 128 captureSession.addOutput(previewOutput2); 129 130 // 提交配置信息 131 await captureSession.commitConfig(); 132 133 // 会话开始 134 await captureSession.start(); 135 } 136 ``` 137 1385. 通过ImageReceiver实时获取预览图像。 139 140 通过ImageReceiver组件中imageArrival事件监听获取底层返回的图像数据,详细的API说明请参考[Image API参考](../reference/apis/js-apis-image.md)。 141 142 ```ts 143 import { BusinessError } from '@ohos.base'; 144 145 function onImageArrival(receiver: image.ImageReceiver): void { 146 receiver.on('imageArrival', () => { 147 receiver.readNextImage((err: BusinessError, nextImage: image.Image) => { 148 if (err || nextImage === undefined) { 149 return; 150 } 151 nextImage.getComponent(image.ComponentType.JPEG, (err: BusinessError, imgComponent: image.Component) => { 152 if (err || imgComponent === undefined) { 153 return; 154 } 155 let buffer: ArrayBuffer; 156 if (imgComponent.byteBuffer as ArrayBuffer) { 157 buffer = imgComponent.byteBuffer; 158 } else { 159 return; 160 } 161 // do something...; 162 }) 163 }) 164 }) 165 } 166 ``` 167