1# 拍照(C/C++)
2
3拍照是相机的最重要功能之一,拍照模块基于相机复杂的逻辑,为了保证用户拍出的照片质量,在中间步骤可以设置分辨率、闪光灯、焦距、照片质量及旋转角度等信息。
4
5## 开发步骤
6
7详细的API说明请参考[Camera API参考](../../reference/apis-camera-kit/_o_h___camera.md)。
8
91. 导入NDK接口,接口中提供了相机相关的属性和方法,导入方法如下。
10
11   ```c++
12    // 导入NDK接口头文件
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. 在CMake脚本中链接相关动态库。
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. 创建并打开相机设备,参考[ 设备输入(C/C++)](./native-camera-device-input.md)步骤3-5。
42
434. 选择设备支持的输出流能力,创建拍照输出流。
44
45   通过[OH_CameraManager_CreatePhotoOutputWithoutSurface()](../../reference/apis-camera-kit/_o_h___camera.md#oh_cameramanager_createphotooutputwithoutsurface)方法创建拍照输出流。
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       // 无需传入surfaceId,直接创建拍照流
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. 注册单段式(PhotoAvailable)拍照回调,若应用希望快速得到回图,推荐使用[分段式拍照回调(PhotoAssetAvailable)](./native-camera-deferred-capture.md)。
82
83   > **注意:**
84   >
85   > 如果已经注册了PhotoAssetAvailable回调,并且在Session开始之后又注册了PhotoAvailable回调,PhotoAssetAvailable和PhotoAvailable同时注册,会导致流被重启,仅PhotoAssetAvailable生效。
86   >
87   > 不建议开发者同时注册PhotoAssetAvailable和PhotoAvailable。
88
89   **单段式拍照开发流程(PhotoAssetAvailable)**:
90
91   - 在会话commitConfig前注册单段式拍照回调。
92   - 在单段式拍照回调函数中获取图片信息,解析出buffer数据,做自定义业务处理。
93   - 将处理完的buffer通过回调传给ArkTS侧,做图片显示或通过安全控件写文件保存图片。
94   - 使用完后解注册单段式拍照回调函数。
95
96   ```c++
97   // 保存NAPI侧注册的buffer处理回调函数
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   // 单段式拍照回调函数
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       // 读取OH_ImageNative的 size 属性
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       // 读取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       // 读取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       // 读取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       // 读取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       // 读取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       // 读取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       // 将ION内存映射到进程空间
147       void *virAddr = nullptr; // 指向映射内存的虚拟地址,解除映射后这个指针将不再有效
148       int32_t ret = OH_NativeBuffer_Map(nativeBuffer, &virAddr); // 映射后通过第二个参数virAddr返回内存的首地址
149       OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_NativeBuffer_Map err:%{public}d", ret);
150       // 调用NAPI层buffer回调
151       auto cb = (void (*)(void *, size_t))(bufferCb);
152       cb(virAddr, nativeBufferSize);
153       // 释放资源
154	   delete[] components;
155	   OH_ImageNative_Release(imageNative);
156       ret = OH_NativeBuffer_Unmap(nativeBuffer); // 在处理完之后,解除映射并释放缓冲区
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   // 注册单段式拍照回调
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   // 解注册单段式拍照回调
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   NAPI层buffer回处理参考示例代码:
187
188   ```c++
189   static napi_ref bufferCbRef_ = nullptr;
190   static napi_env env_;
191   size_t g_size = 0;
192
193   // NAPI层buffer回调方法
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       // 使用 std::memcpy 复制 buffer 的内容到 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               // 调用ArkTS的buffer处理回调函数,将图片arrayBuffer传给页面做显示或保存
227               napi_call_function(env, nullptr, callback, 1, &arrayBuffer, &retVal);
228               // 清理内存
229               free(data); // 释放在异步工作中分配的内存
230           },
231           copyBuffer, &work);
232
233       // 错误检查:创建异步工作失败时释放内存
234       if (status != napi_ok) {
235           OH_LOG_ERROR(LOG_APP, "Failed to create async work");
236           free(copyBuffer); // 释放分配的内存
237           return;
238       }
239       napi_queue_async_work_with_qos(env_, work, napi_qos_user_initiated);
240   }
241
242   // 保存ArkTS侧传入的buffer处理回调函数
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       // 注册ArkTS侧buffer回调到NAPI层
260       ndkCamera_->RegisterBufferCb((void *)BufferCb);
261       return result;
262   }
263   ```
264
265   ArkTS侧buffer处理参考示例代码:
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     // ArrayBuffer处理回调函数
317     photoBufferCallback: (arrayBuffer: ArrayBuffer) => void = (arrayBuffer: ArrayBuffer) => {
318       console.info('photoBufferCallback')
319       // 处理方式一:创建PixelMap显示图片
320       let imageSource = image.createImageSource(arrayBuffer);
321       imageSource.createPixelMap((err: BusinessError, data: image.PixelMap) => {
322         this.curPixelMap = data;
323         this.showImage = true;
324       })
325       // 处理方式二:通过安全控件写文件保存图片
326       fileIo.write(this.file?.fd, arrayBuffer)
327         .then(() => {
328           console.info('file write OK');
329           // 关闭文件
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                 // 调用NDK接口初始化相机
362                 await cameraDemo.initCamera(this.surfaceId);
363                 // 注册ArkTS侧buffer处理回调
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             // 显示拍照得到的图片
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           // 安全控件,用来保存媒体资源
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                 // onClick触发后10秒内通过createAsset接口创建图片文件,10秒后createAsset权限收回。
388                 let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
389                 console.error('uri:' + uri);
390                 // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制
391                 this.file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
392                 // 调用NDK接口拍照,触发PhotoAvailable回调
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. 创建拍照类型会话,参考[会话管理(C/C++)](./native-camera-session-management.md),开启会话,准备拍照。
411
412   ```c++
413   // 创建相机会话
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   // 设置会话模式为拍照模式
420   Camera_SceneMode sceneMode = NORMAL_PHOTO;
421   ret = OH_CaptureSession_SetSessionMode(captureSession, sceneMode);
422   // 配置会话开始
423   ret = OH_CaptureSession_BeginConfig(captureSession);
424   ```
425
4267. 配置拍照参数(可选)。
427   配置相机的参数可以调整拍照的一些功能,包括闪光灯、变焦、焦距等。
428
429   ```c++
430   // 判断设备是否支持闪光灯
431    Camera_FlashMode flashMode = FLASH_MODE_AUTO;
432    bool hasFlash = false;
433    ret = OH_CaptureSession_HasFlash(captureSession, &hasFlash);
434    if (ret != CAMERA_OK) {
435        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_HasFlash failed.");
436    }
437    if (hasFlash) {
438        OH_LOG_INFO(LOG_APP, "hasFlash success");
439    } else {
440        OH_LOG_ERROR(LOG_APP, "hasFlash fail");
441    }
442    // 检测闪光灯模式是否支持
443    bool isSupported = false;
444    ret = OH_CaptureSession_IsFlashModeSupported(captureSession, flashMode, &isSupported);
445    if (ret != CAMERA_OK) {
446        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFlashModeSupported failed.");
447    }
448    if (isSupported) {
449        OH_LOG_INFO(LOG_APP, "isFlashModeSupported success");
450        // 设置闪光灯模式
451        ret = OH_CaptureSession_SetFlashMode(captureSession, flashMode);
452        if (ret == CAMERA_OK) {
453            OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetFlashMode success.");
454        } else {
455            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFlashMode failed. %{public}d ", ret);
456        }
457        // 获取当前设备的闪光灯模式
458        ret = OH_CaptureSession_GetFlashMode(captureSession, &flashMode);
459        if (ret == CAMERA_OK) {
460            OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFlashMode success. flashMode:%{public}d ", flashMode);
461        } else {
462            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFlashMode failed. %d ", ret);
463        }
464    } else {
465        OH_LOG_ERROR(LOG_APP, "isFlashModeSupported fail");
466    }
467
468    // 判断是否支持连续自动变焦模式
469    Camera_FocusMode focusMode = FOCUS_MODE_CONTINUOUS_AUTO;
470    bool isFocusModeSupported = false;
471    ret = OH_CaptureSession_IsFocusModeSupported(captureSession, focusMode, &isFocusModeSupported);
472    if (ret != CAMERA_OK) {
473        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFocusModeSupported failed.");
474    }
475    if (isFocusModeSupported) {
476        OH_LOG_INFO(LOG_APP, "isFocusModeSupported success");
477        ret = OH_CaptureSession_SetFocusMode(captureSession, focusMode);
478        if (ret != CAMERA_OK) {
479            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFocusMode failed. %{public}d ", ret);
480        }
481        ret = OH_CaptureSession_GetFocusMode(captureSession, &focusMode);
482        if (ret == CAMERA_OK) {
483            OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFocusMode success. focusMode%{public}d ", focusMode);
484        } else {
485            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFocusMode failed. %d ", ret);
486        }
487    } else {
488        OH_LOG_ERROR(LOG_APP, "isFocusModeSupported fail");
489    }
490
491    // 获取相机支持的可变焦距比范围
492    float minZoom;
493    float maxZoom;
494    ret = OH_CaptureSession_GetZoomRatioRange(captureSession, &minZoom, &maxZoom);
495    if (ret != CAMERA_OK) {
496        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatioRange failed.");
497    } else {
498        OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatioRange success. minZoom: %{public}f, maxZoom:%{public}f",
499            minZoom, maxZoom);
500    }
501    // 设置变焦
502    ret = OH_CaptureSession_SetZoomRatio(captureSession, maxZoom);
503    if (ret == CAMERA_OK) {
504        OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetZoomRatio success.");
505    } else {
506        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetZoomRatio failed. %{public}d ", ret);
507    }
508    // 获取当前设备的变焦值
509    ret = OH_CaptureSession_GetZoomRatio(captureSession, &maxZoom);
510    if (ret == CAMERA_OK) {
511        OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatio success. zoom:%{public}f ", maxZoom);
512    } else {
513        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatio failed. %{public}d ", ret);
514    }
515   ```
516
5178. 触发拍照。
518
519    通过OH_PhotoOutput_Capture()方法,执行拍照任务。
520
521     ```c++
522      ret = OH_PhotoOutput_Capture(photoOutput);
523      if (ret == CAMERA_OK) {
524          OH_LOG_INFO(LOG_APP, "OH_PhotoOutput_Capture success ");
525      } else {
526          OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_Capture failed. %d ", ret);
527      }
528     ```
529
530## 状态监听
531
532在相机应用开发过程中,可以随时监听拍照输出流状态,包括拍照流开始、拍照帧的开始与结束、拍照输出流的错误。
533
534- 通过注册固定的onFrameStart回调函数获取监听拍照开始结果,photoOutput创建成功时即可监听,拍照第一次曝光时触发。
535
536  ```c++
537    ret = OH_PhotoOutput_RegisterCallback(photoOutput, GetPhotoOutputListener());
538    if (ret != CAMERA_OK) {
539        OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_RegisterCallback failed.");
540    }
541  ```
542  ```c++
543    void PhotoOutputOnFrameStart(Camera_PhotoOutput* photoOutput)
544    {
545        OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameStart");
546    }
547    void PhotoOutputOnFrameShutter(Camera_PhotoOutput* photoOutput, Camera_FrameShutterInfo* info)
548    {
549        OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameShutter");
550    }
551    PhotoOutput_Callbacks* GetPhotoOutputListener()
552    {
553        static PhotoOutput_Callbacks photoOutputListener = {
554            .onFrameStart = PhotoOutputOnFrameStart,
555            .onFrameShutter = PhotoOutputOnFrameShutter,
556            .onFrameEnd = PhotoOutputOnFrameEnd,
557            .onError = PhotoOutputOnError
558        };
559        return &photoOutputListener;
560    }
561  ```
562
563- 通过注册固定的onFrameEnd回调函数获取监听拍照结束结果,photoOutput创建成功时即可监听。
564
565  ```c++
566    void PhotoOutputOnFrameEnd(Camera_PhotoOutput* photoOutput, int32_t frameCount)
567    {
568        OH_LOG_INFO(LOG_APP, "PhotoOutput frameCount = %{public}d", frameCount);
569    }
570  ```
571
572- 通过注册固定的onError回调函数获取监听拍照输出流的错误结果。callback返回拍照输出接口使用错误时的对应错误码,错误码类型参见[Camera_ErrorCode](../../reference/apis-camera-kit/_o_h___camera.md#camera_errorcode-1)。
573
574  ```c++
575    void PhotoOutputOnError(Camera_PhotoOutput* photoOutput, Camera_ErrorCode errorCode)
576    {
577        OH_LOG_INFO(LOG_APP, "PhotoOutput errorCode = %{public}d", errorCode);
578    }
579  ```