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