1# Photo Capture (C/C++) 2 3Photo capture is an important function of the camera application. Based on the complex logic of the camera hardware, the camera module provides APIs for you to set information such as resolution, flash, focal length, photo quality, and rotation angle. 4 5## How to Develop 6 7Read [Camera](../../reference/apis-camera-kit/_o_h___camera.md) for the API reference. 8 91. Import the NDK, which provides camera-related attributes and methods. 10 11 ```c++ 12 // Include the NDK header files. 13 #include <cstdint> 14 #include <cstdlib> 15 #include <cstring> 16 #include <string.h> 17 #include "hilog/log.h" 18 #include "ohcamera/camera.h" 19 #include "ohcamera/camera_input.h" 20 #include "ohcamera/capture_session.h" 21 #include "ohcamera/photo_output.h" 22 #include "ohcamera/preview_output.h" 23 #include "ohcamera/video_output.h" 24 #include "ohcamera/camera_manager.h" 25 #include <multimedia/image_framework/image/image_native.h> 26 ``` 27 282. Link the dynamic library in the CMake script. 29 30 ```txt 31 target_link_libraries(entry PUBLIC 32 libace_napi.z.so 33 libhilog_ndk.z.so 34 libnative_buffer.so 35 libohcamera.so 36 libohimage.so 37 libohfileuri.so 38 ) 39 ``` 40 413. Create and open a camera device. For details, see steps 3 to 5 in [Device Input Management (C/C++)](./native-camera-device-input.md). 42 434. Select the output stream capability supported by the camera device and create a photo output stream. 44 45 Call [OH_CameraManager_CreatePhotoOutputWithoutSurface()](../../reference/apis-camera-kit/_o_h___camera.md#oh_cameramanager_createphotooutputwithoutsurface) to create a photo output stream. 46 47 ```c++ 48 void CreatePhotoOutput() { 49 Camera_Manager *cameraManager = nullptr; 50 Camera_Device *cameras = nullptr; 51 Camera_OutputCapability *cameraOutputCapability = nullptr; 52 Camera_PhotoOutput *photoOutput = nullptr; 53 const Camera_Profile *photoProfile = nullptr; 54 uint32_t size = 0; 55 uint32_t cameraDeviceIndex = 0; 56 Camera_ErrorCode ret = OH_Camera_GetCameraManager(&cameraManager); 57 if (cameraManager == nullptr || ret != CAMERA_OK) { 58 OH_LOG_ERROR(LOG_APP, "OH_Camera_GetCameraManager failed."); 59 } 60 ret = OH_CameraManager_GetSupportedCameras(cameraManager, &cameras, &size); 61 if (cameras == nullptr || size < 0 || ret != CAMERA_OK) { 62 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameras failed."); 63 } 64 ret = OH_CameraManager_GetSupportedCameraOutputCapability(cameraManager, &cameras[cameraDeviceIndex], 65 &cameraOutputCapability); 66 if (cameraOutputCapability == nullptr || ret != CAMERA_OK) { 67 OH_LOG_ERROR(LOG_APP, "GetSupportedCameraOutputCapability failed."); 68 } 69 photoProfile = cameraOutputCapability->photoProfiles[0]; 70 if (photoProfile == nullptr) { 71 OH_LOG_ERROR(LOG_APP, "Get photoProfiles failed."); 72 } 73 // Create a photo output stream without passing a surface ID. 74 ret = OH_CameraManager_CreatePhotoOutputWithoutSurface(cameraManager, photoProfile, &photoOutput); 75 if (photoOutput == nullptr || ret != CAMERA_OK) { 76 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePhotoOutputWithoutSurface failed."); 77 } 78 } 79 ``` 80 815. Register a one-time photo capture callback, which is defined as **PhotoAvailable**. If your application requires rapid image display, use the deferred photo delivery callback, which is defined as [**PhotoAssetAvailable**](./native-camera-deferred-capture.md). 82 83 > **NOTE** 84 > 85 > If the **PhotoAssetAvailable** callback has been registered and the **PhotoAvailable** callback is registered after the session starts, the stream will be restarted. In this case, only the **PhotoAssetAvailable** callback takes effect. 86 > 87 > Therefore, you are not advised to register both **PhotoAssetAvailable** and **PhotoAvailable**. 88 89 The development process is as follows: 90 91 - Register the callback before the session commits the configuration. 92 - Obtain the image information from the callback, parse the buffer data, and perform custom service processing. 93 - Pass the processed buffer to the ArkTS side through the callback for image display or storage (using a security component). 94 - Unregister the callback when it is no longer required. 95 96 ```c++ 97 // Save the buffer processing callback registered on the NAPI side. 98 static void *bufferCb = nullptr; 99 Camera_ErrorCode NDKCamera::RegisterBufferCb(void *cb) { 100 OH_LOG_INFO(LOG_APP, " RegisterBufferCb start"); 101 if (cb == nullptr) { 102 OH_LOG_INFO(LOG_APP, " RegisterBufferCb invalid error"); 103 return CAMERA_INVALID_ARGUMENT; 104 } 105 bufferCb = cb; 106 return CAMERA_OK; 107 } 108 109 // One-time photo capture callback. 110 void OnPhotoAvailable(Camera_PhotoOutput *photoOutput, OH_PhotoNative *photo) { 111 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable start!"); 112 OH_ImageNative *imageNative; 113 Camera_ErrorCode errCode = OH_PhotoNative_GetMainImage(photo, &imageNative); 114 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable errCode:%{public}d imageNative:%{public}p", errCode, imageNative); 115 // Read the size attribute of OH_ImageNative. 116 Image_Size size; 117 Image_ErrorCode imageErr = OH_ImageNative_GetImageSize(imageNative, &size); 118 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d width:%{public}d height:%{public}d", imageErr, 119 size.width, size.height); 120 // Read the number of elements in the component list of OH_ImageNative. 121 size_t componentTypeSize = 0; 122 imageErr = OH_ImageNative_GetComponentTypes(imageNative, nullptr, &componentTypeSize); 123 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d componentTypeSize:%{public}zu", imageErr, 124 componentTypeSize); 125 // Read the component list of OH_ImageNative. 126 uint32_t *components = new uint32_t[componentTypeSize]; 127 imageErr = OH_ImageNative_GetComponentTypes(imageNative, &components, &componentTypeSize); 128 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_ImageNative_GetComponentTypes imageErr:%{public}d", imageErr); 129 // Read the buffer object corresponding to the first component of OH_ImageNative. 130 OH_NativeBuffer *nativeBuffer = nullptr; 131 imageErr = OH_ImageNative_GetByteBuffer(imageNative, components[0], &nativeBuffer); 132 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_ImageNative_GetByteBuffer imageErr:%{public}d", imageErr); 133 // Read the size of the buffer corresponding to the first component of OH_ImageNative. 134 size_t nativeBufferSize = 0; 135 imageErr = OH_ImageNative_GetBufferSize(imageNative, components[0], &nativeBufferSize); 136 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d nativeBufferSize:%{public}zu", imageErr, 137 nativeBufferSize); 138 // Read the row stride corresponding to the first component of OH_ImageNative. 139 int32_t rowStride = 0; 140 imageErr = OH_ImageNative_GetRowStride(imageNative, components[0], &rowStride); 141 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d rowStride:%{public}d", imageErr, rowStride); 142 // Read the pixel stride corresponding to the first component of OH_ImageNative. 143 int32_t pixelStride = 0; 144 imageErr = OH_ImageNative_GetPixelStride(imageNative, components[0], &pixelStride); 145 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d pixelStride:%{public}d", imageErr, pixelStride); 146 // Map the ION memory to the process address space. 147 void *virAddr = nullptr; // Point to the virtual address of the mapped memory. After unmapping, the pointer is invalid. 148 int32_t ret = OH_NativeBuffer_Map(nativeBuffer, &virAddr); // After mapping, the start address of the memory is returned through the parameter virAddr. 149 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_NativeBuffer_Map err:%{public}d", ret); 150 // Call the buffer callback at the NAPI layer. 151 auto cb = (void (*)(void *, size_t))(bufferCb); 152 cb(virAddr, nativeBufferSize); 153 // Release resources. 154 delete[] components; 155 OH_ImageNative_Release(imageNative); 156 ret = OH_NativeBuffer_Unmap(nativeBuffer); // After the processing is complete, unmap and release the buffer. 157 if (ret != 0) { 158 OH_LOG_ERROR(LOG_APP, "OnPhotoAvailable OH_NativeBuffer_Unmap error:%{public}d", ret); 159 } 160 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable end"); 161 } 162 163 // Register the PhotoAvailableCallback callback. 164 Camera_ErrorCode NDKCamera::PhotoOutputRegisterPhotoAvailableCallback(Camera_PhotoOutput* photoOutput) { 165 OH_LOG_INFO(LOG_APP, "PhotoOutputRegisterPhotoAvailableCallback start!"); 166 Camera_ErrorCode errCode = OH_PhotoOutput_RegisterPhotoAvailableCallback(photoOutput, OnPhotoAvailable); 167 if (errCode != CAMERA_OK) { 168 OH_LOG_ERROR(LOG_APP, "PhotoOutputRegisterPhotoAvailableCallback failed."); 169 } 170 OH_LOG_INFO(LOG_APP, "PhotoOutputRegisterPhotoAvailableCallback return with ret code: %{public}d!", errCode); 171 return errCode; 172 } 173 174 // Unregister the PhotoAvailableCallback callback. 175 Camera_ErrorCode NDKCamera::PhotoOutputUnRegisterPhotoAvailableCallback(Camera_PhotoOutput* photoOutput) { 176 OH_LOG_INFO(LOG_APP, "PhotoOutputUnRegisterPhotoAvailableCallback start!"); 177 ret_ = OH_PhotoOutput_UnregisterPhotoAvailableCallback(photoOutput, OnPhotoAvailable); 178 if (ret_ != CAMERA_OK) { 179 OH_LOG_ERROR(LOG_APP, "PhotoOutputUnRegisterPhotoAvailableCallback failed."); 180 } 181 OH_LOG_INFO(LOG_APP, "PhotoOutputUnRegisterPhotoAvailableCallback return with ret code: %{public}d!", ret_); 182 return ret_; 183 } 184 ``` 185 186 Sample code for buffer processing at the NAPI layer: 187 188 ```c++ 189 static napi_ref bufferCbRef_ = nullptr; 190 static napi_env env_; 191 size_t g_size = 0; 192 193 // Buffer callback at the NAPI layer. 194 static void BufferCb(void *buffer, size_t size) { 195 OH_LOG_INFO(LOG_APP, "BufferCb size:%{public}zu", size); 196 g_size = size; 197 napi_value asyncResource = nullptr; 198 napi_value asyncResourceName = nullptr; 199 napi_async_work work; 200 201 void *copyBuffer = malloc(size); 202 if (copyBuffer == nullptr) { 203 return; 204 } 205 OH_LOG_INFO(LOG_APP, "BufferCb copyBuffer:%{public}p", copyBuffer); 206 // Use std::memcpy to copy the content in the buffer to the copyBuffer. 207 std::memcpy(copyBuffer, buffer, size); 208 napi_create_string_utf8(env_, "BufferCb", NAPI_AUTO_LENGTH, &asyncResourceName); 209 napi_status status = napi_create_async_work( 210 env_, asyncResource, asyncResourceName, [](napi_env env, void *copyBuffer) {}, 211 [](napi_env env, napi_status status, void *copyBuffer) { 212 napi_value retVal; 213 napi_value callback = nullptr; 214 void *data = nullptr; 215 napi_value arrayBuffer = nullptr; 216 size_t bufferSize = g_size; 217 napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer); 218 std::memcpy(data, copyBuffer, bufferSize); 219 OH_LOG_INFO(LOG_APP, "BufferCb g_size: %{public}zu", g_size); 220 napi_get_reference_value(env, bufferCbRef_, &callback); 221 if (callback) { 222 OH_LOG_INFO(LOG_APP, "BufferCb callback is full"); 223 } else { 224 OH_LOG_ERROR(LOG_APP, "BufferCb callback is null"); 225 } 226 // Call the buffer processing callback function at the ArkTS side to pass the image arrayBuffer for display or storage. 227 napi_call_function(env, nullptr, callback, 1, &arrayBuffer, &retVal); 228 // Clear the memory. 229 free(data); // Release the memory allocated during asynchronous work. 230 }, 231 copyBuffer, &work); 232 233 // Error check: The memory is released when the asynchronous work fails to be created. 234 if (status != napi_ok) { 235 OH_LOG_ERROR(LOG_APP, "Failed to create async work"); 236 free(copyBuffer); // Release the allocated memory. 237 return; 238 } 239 napi_queue_async_work_with_qos(env_, work, napi_qos_user_initiated); 240 } 241 242 // Save the buffer processing callback function passed from ArkTS. 243 static napi_value SetBufferCb(napi_env env, napi_callback_info info) { 244 OH_LOG_INFO(LOG_APP, "SetBufferCb start"); 245 napi_value result; 246 napi_get_undefined(env, &result); 247 248 napi_value argValue[1] = {nullptr}; 249 size_t argCount = 1; 250 napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr); 251 252 env_ = env; 253 napi_create_reference(env, argValue[0], 1, &bufferCbRef_); 254 if (bufferCbRef_) { 255 OH_LOG_INFO(LOG_APP, "SetBufferCb callbackRef is full"); 256 } else { 257 OH_LOG_ERROR(LOG_APP, "SetBufferCb callbackRef is null"); 258 } 259 // Register the buffer callback to be passed to the NAPI layer on the ArkTS side. 260 ndkCamera_->RegisterBufferCb((void *)BufferCb); 261 return result; 262 } 263 ``` 264 265 Sample code for buffer processing on the ArkTS side: 266 267 ```ts 268 /* 269 * Copyright (c) 2024 Huawei Device Co., Ltd. 270 * Licensed under the Apache License, Version 2.0 (the 'License'); 271 * you may not use this file except in compliance with the License. 272 * You may obtain a copy of the License at 273 * 274 * http://www.apache.org/licenses/LICENSE-2.0 275 * 276 * Unless required by applicable law or agreed to in writing, software 277 * distributed under the License is distributed on an 'AS IS' BASIS, 278 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 279 * See the License for the specific language governing permissions and 280 * limitations under the License. 281 */ 282 283 import { image } from '@kit.ImageKit'; 284 import { photoAccessHelper } from '@kit.MediaLibraryKit'; 285 import { fileIo } from '@kit.CoreFileKit'; 286 import { BusinessError } from '@kit.BasicServicesKit'; 287 import cameraDemo from 'libentry.so'; 288 289 interface PhotoSettings { 290 quality: number, // Photo quality 291 rotation: number, // Photo direction 292 mirror: boolean, // Mirror Enable 293 latitude: number, // geographic location 294 longitude: number, // geographic location 295 altitude: number // geographic location 296 }; 297 298 @Entry 299 @Component 300 struct Index { 301 private mXComponentController: XComponentController = new XComponentController(); 302 private surfaceId = ''; 303 private file: fileIo.File | undefined; 304 @State imageWidth: number = 1920; 305 @State imageHeight: number = 1080; 306 @State showImage: boolean = false; 307 @State curPixelMap: image.PixelMap | undefined = undefined; 308 photoSettings: PhotoSettings = { 309 quality: 0, 310 rotation: 0, 311 mirror: false, 312 latitude: 12.9698, 313 longitude: 77.7500, 314 altitude: 1000 315 }; 316 // Process the ArrayBuffer in the callback. 317 photoBufferCallback: (arrayBuffer: ArrayBuffer) => void = (arrayBuffer: ArrayBuffer) => { 318 console.info('photoBufferCallback') 319 // Method 1: Create a PixelMap for image display. 320 let imageSource = image.createImageSource(arrayBuffer); 321 imageSource.createPixelMap((err: BusinessError, data: image.PixelMap) => { 322 this.curPixelMap = data; 323 this.showImage = true; 324 }) 325 // Method 2: Use the security component to write a file and save the image. 326 fileIo.write(this.file?.fd, arrayBuffer) 327 .then(() => { 328 console.info('file write OK'); 329 // Close the file. 330 fileIo.close(this.file); 331 }).catch(() => { 332 console.error('file write failed'); 333 }) 334 } 335 336 onPageShow(): void { 337 } 338 339 onPageHide(): void { 340 cameraDemo.releaseCamera(); 341 } 342 343 build() { 344 Column() { 345 Column() { 346 if (!this.showImage) { 347 XComponent({ 348 id: 'componentId', 349 type: 'surface', 350 controller: this.mXComponentController 351 }) 352 .onLoad(async () => { 353 console.info('onLoad is called'); 354 this.surfaceId = this.mXComponentController.getXComponentSurfaceId(); 355 let surfaceRect: SurfaceRect = { 356 surfaceWidth: this.imageHeight, 357 surfaceHeight: this.imageWidth 358 }; 359 this.mXComponentController.setXComponentSurfaceRect(surfaceRect); 360 console.info(`onLoad surfaceId: ${this.surfaceId}`); 361 // Call the NDK API to initialize the camera. 362 await cameraDemo.initCamera(this.surfaceId); 363 // Register the buffer processing callback on the ArkTS side. 364 cameraDemo.setBufferCb(this.photoBufferCallback); 365 })// The width and height of the surface are opposite to those of the XComponent. 366 .width(px2vp(this.imageHeight)) 367 .height(px2vp(this.imageWidth)) 368 } 369 370 if (this.showImage) { 371 // Display the captured image. 372 Image(this.curPixelMap) 373 .width(px2vp(this.imageHeight)) 374 .height(px2vp(this.imageWidth)) 375 } 376 377 } 378 .justifyContent(FlexAlign.Center) 379 .height('80%') 380 381 // Security component, which is used to store media resources. 382 SaveButton({text:SaveDescription.SAVE_IMAGE}).onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => { 383 if (result == SaveButtonOnClickResult.SUCCESS) { 384 try { 385 const context = getContext(this); 386 let helper = photoAccessHelper.getPhotoAccessHelper(context); 387 // After onClick is triggered, the createAsset API can be called within 10 seconds to create an image file. After 10 seconds have elapsed, the permission to call createAsset is revoked. 388 let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); 389 console.error('uri:' + uri); 390 // Open the file based on its URI. The write process is not time bound. 391 this.file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); 392 // Call the NDK API to take a photo and trigger the PhotoAvailable callback. 393 cameraDemo.takePictureWithSettings(this.photoSettings); 394 } catch (error) { 395 console.error("error is " + JSON.stringify(error)); 396 } 397 } 398 }) 399 400 Text('NdkPhotoAvailableDemo') 401 .fontSize(30) 402 } 403 .justifyContent(FlexAlign.End) 404 .height('100%') 405 .width('100%') 406 } 407 } 408 ``` 409 4106. Create a photo session. For details, see [Camera Session Management (C/C++)](./native-camera-session-management.md). 411 412 ```c++ 413 // Create a camera session. 414 Camera_CaptureSession* captureSession = nullptr; 415 Camera_ErrorCode ret = OH_CameraManager_CreateCaptureSession(cameraManager, &captureSession); 416 if (captureSession == nullptr || ret != CAMERA_OK) { 417 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCaptureSession failed."); 418 } 419 // Set the session mode to the photo mode. 420 Camera_SceneMode sceneMode = NORMAL_PHOTO; 421 ret = OH_CaptureSession_SetSessionMode(captureSession, sceneMode); 422 // Start session configuration. 423 ret = OH_CaptureSession_BeginConfig(captureSession); 424 ``` 425 4267. (Optional) Set photo capture parameters. 427 428 You can set camera parameters to adjust photo capture functions, including the flash, zoom ratio, and focal length. 429 430 ```c++ 431 // Check whether the camera has flash. 432 Camera_FlashMode flashMode = FLASH_MODE_AUTO; 433 bool hasFlash = false; 434 ret = OH_CaptureSession_HasFlash(captureSession, &hasFlash); 435 if (ret != CAMERA_OK) { 436 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_HasFlash failed."); 437 } 438 if (hasFlash) { 439 OH_LOG_INFO(LOG_APP, "hasFlash success"); 440 } else { 441 OH_LOG_ERROR(LOG_APP, "hasFlash fail"); 442 } 443 // Check whether a flash mode is supported. 444 bool isSupported = false; 445 ret = OH_CaptureSession_IsFlashModeSupported(captureSession, flashMode, &isSupported); 446 if (ret != CAMERA_OK) { 447 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFlashModeSupported failed."); 448 } 449 if (isSupported) { 450 OH_LOG_INFO(LOG_APP, "isFlashModeSupported success"); 451 // Set the flash mode. 452 ret = OH_CaptureSession_SetFlashMode(captureSession, flashMode); 453 if (ret == CAMERA_OK) { 454 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetFlashMode success."); 455 } else { 456 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFlashMode failed. %{public}d ", ret); 457 } 458 // Obtain the flash mode in use. 459 ret = OH_CaptureSession_GetFlashMode(captureSession, &flashMode); 460 if (ret == CAMERA_OK) { 461 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFlashMode success. flashMode: %{public}d ", flashMode); 462 } else { 463 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFlashMode failed. %d ", ret); 464 } 465 } else { 466 OH_LOG_ERROR(LOG_APP, "isFlashModeSupported fail"); 467 } 468 469 // Check whether the continuous auto focus is supported. 470 Camera_FocusMode focusMode = FOCUS_MODE_CONTINUOUS_AUTO; 471 bool isFocusModeSupported = false; 472 ret = OH_CaptureSession_IsFocusModeSupported(captureSession, focusMode, &isFocusModeSupported); 473 if (ret != CAMERA_OK) { 474 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFocusModeSupported failed."); 475 } 476 if (isFocusModeSupported) { 477 OH_LOG_INFO(LOG_APP, "isFocusModeSupported success"); 478 ret = OH_CaptureSession_SetFocusMode(captureSession, focusMode); 479 if (ret != CAMERA_OK) { 480 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFocusMode failed. %{public}d ", ret); 481 } 482 ret = OH_CaptureSession_GetFocusMode(captureSession, &focusMode); 483 if (ret == CAMERA_OK) { 484 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFocusMode success. focusMode%{public}d ", focusMode); 485 } else { 486 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFocusMode failed. %d ", ret); 487 } 488 } else { 489 OH_LOG_ERROR(LOG_APP, "isFocusModeSupported fail"); 490 } 491 492 // Obtain the zoom ratio range supported by the camera. 493 float minZoom; 494 float maxZoom; 495 ret = OH_CaptureSession_GetZoomRatioRange(captureSession, &minZoom, &maxZoom); 496 if (ret != CAMERA_OK) { 497 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatioRange failed."); 498 } else { 499 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatioRange success. minZoom: %{public}f, maxZoom:%{public}f", 500 minZoom, maxZoom); 501 } 502 // Set a zoom ratio. 503 ret = OH_CaptureSession_SetZoomRatio(captureSession, maxZoom); 504 if (ret == CAMERA_OK) { 505 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetZoomRatio success."); 506 } else { 507 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetZoomRatio failed. %{public}d ", ret); 508 } 509 // Obtain the zoom ratio of the camera. 510 ret = OH_CaptureSession_GetZoomRatio(captureSession, &maxZoom); 511 if (ret == CAMERA_OK) { 512 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatio success. zoom: %{public}f ", maxZoom); 513 } else { 514 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatio failed. %{public}d ", ret); 515 } 516 ``` 517 5188. Trigger photo capture. 519 520 Call **OH_PhotoOutput_Capture()**. 521 522 ```c++ 523 ret = OH_PhotoOutput_Capture(photoOutput); 524 if (ret == CAMERA_OK) { 525 OH_LOG_INFO(LOG_APP, "OH_PhotoOutput_Capture success "); 526 } else { 527 OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_Capture failed. %d ", ret); 528 } 529 ``` 530 531## Status Listening 532 533During camera application development, you can listen for the status of the photo output stream, including the start of the photo stream, the start and end of the photo frame, and the errors of the photo output stream. 534 535- Register the **'onFrameStart'** event to listen for photo capture start events. This event can be registered when a **PhotoOutput** instance is created and is triggered when the bottom layer starts exposure for photo capture for the first time. The capture ID is returned. 536 537 ```c++ 538 ret = OH_PhotoOutput_RegisterCallback(photoOutput, GetPhotoOutputListener()); 539 if (ret != CAMERA_OK) { 540 OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_RegisterCallback failed."); 541 } 542 ``` 543 ```c++ 544 void PhotoOutputOnFrameStart(Camera_PhotoOutput* photoOutput) 545 { 546 OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameStart"); 547 } 548 void PhotoOutputOnFrameShutter(Camera_PhotoOutput* photoOutput, Camera_FrameShutterInfo* info) 549 { 550 OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameShutter"); 551 } 552 PhotoOutput_Callbacks* GetPhotoOutputListener() 553 { 554 static PhotoOutput_Callbacks photoOutputListener = { 555 .onFrameStart = PhotoOutputOnFrameStart, 556 .onFrameShutter = PhotoOutputOnFrameShutter, 557 .onFrameEnd = PhotoOutputOnFrameEnd, 558 .onError = PhotoOutputOnError 559 }; 560 return &photoOutputListener; 561 } 562 ``` 563 564- Register the **'onFrameEnd'** event to listen for photo capture end events. This event can be registered when a **PhotoOutput** instance is created. 565 566 ```c++ 567 void PhotoOutputOnFrameEnd(Camera_PhotoOutput* photoOutput, int32_t frameCount) 568 { 569 OH_LOG_INFO(LOG_APP, "PhotoOutput frameCount = %{public}d", frameCount); 570 } 571 ``` 572 573- Register the **'onError'** event to listen for photo output errors. The callback function returns an error code when an API is incorrectly used. For details about the error code types, see [Camera_ErrorCode](../../reference/apis-camera-kit/_o_h___camera.md#camera_errorcode-1). 574 575 ```c++ 576 void PhotoOutputOnError(Camera_PhotoOutput* photoOutput, Camera_ErrorCode errorCode) 577 { 578 OH_LOG_INFO(LOG_APP, "PhotoOutput errorCode = %{public}d", errorCode); 579 } 580 ``` 581