• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       ret = OH_NativeBuffer_Unmap(nativeBuffer);
155       if (ret != 0) {
156           OH_LOG_ERROR(LOG_APP, "OnPhotoAvailable OH_NativeBuffer_Unmap error:%{public}d", ret);
157       }
158   }
159
160   // 注册单段式拍照回调
161   Camera_ErrorCode NDKCamera::PhotoOutputRegisterPhotoAvailableCallback(Camera_PhotoOutput* photoOutput) {
162       OH_LOG_INFO(LOG_APP, "PhotoOutputRegisterPhotoAvailableCallback start!");
163       Camera_ErrorCode errCode = OH_PhotoOutput_RegisterPhotoAvailableCallback(photoOutput, OnPhotoAvailable);
164       if (errCode != CAMERA_OK) {
165           OH_LOG_ERROR(LOG_APP, "PhotoOutputRegisterPhotoAvailableCallback failed.");
166       }
167       OH_LOG_INFO(LOG_APP, "PhotoOutputRegisterPhotoAvailableCallback return with ret code: %{public}d!", errCode);
168       return errCode;
169   }
170
171   // 解注册单段式拍照回调
172   Camera_ErrorCode NDKCamera::PhotoOutputUnRegisterPhotoAvailableCallback(Camera_PhotoOutput* photoOutput) {
173       OH_LOG_INFO(LOG_APP, "PhotoOutputUnRegisterPhotoAvailableCallback start!");
174       ret_ = OH_PhotoOutput_UnregisterPhotoAvailableCallback(photoOutput, OnPhotoAvailable);
175       if (ret_ != CAMERA_OK) {
176           OH_LOG_ERROR(LOG_APP, "PhotoOutputUnRegisterPhotoAvailableCallback failed.");
177       }
178       OH_LOG_INFO(LOG_APP, "PhotoOutputUnRegisterPhotoAvailableCallback return with ret code: %{public}d!", ret_);
179       return ret_;
180   }
181   ```
182
183   NAPI层buffer回处理参考示例代码:
184
185   ```c++
186   static napi_ref bufferCbRef_ = nullptr;
187   static napi_env env_;
188   size_t g_size = 0;
189
190   // NAPI层buffer回调方法
191   static void BufferCb(void *buffer, size_t size) {
192       OH_LOG_INFO(LOG_APP, "BufferCb size:%{public}zu", size);
193       g_size = size;
194       napi_value asyncResource = nullptr;
195       napi_value asyncResourceName = nullptr;
196       napi_async_work work;
197
198       void *copyBuffer = malloc(size);
199       if (copyBuffer == nullptr) {
200           return;
201       }
202       OH_LOG_INFO(LOG_APP, "BufferCb copyBuffer:%{public}p", copyBuffer);
203       // 使用 std::memcpy 复制 buffer 的内容到 copyBuffer
204       std::memcpy(copyBuffer, buffer, size);
205       napi_create_string_utf8(env_, "BufferCb", NAPI_AUTO_LENGTH, &asyncResourceName);
206       napi_status status = napi_create_async_work(
207           env_, asyncResource, asyncResourceName, [](napi_env env, void *copyBuffer) {},
208           [](napi_env env, napi_status status, void *copyBuffer) {
209               napi_value retVal;
210               napi_value callback = nullptr;
211               void *data = nullptr;
212               napi_value arrayBuffer = nullptr;
213               size_t bufferSize = g_size;
214               napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer);
215               std::memcpy(data, copyBuffer, bufferSize);
216               OH_LOG_INFO(LOG_APP, "BufferCb g_size: %{public}zu", g_size);
217               napi_get_reference_value(env, bufferCbRef_, &callback);
218               if (callback) {
219                   OH_LOG_INFO(LOG_APP, "BufferCb callback is full");
220               } else {
221                   OH_LOG_ERROR(LOG_APP, "BufferCb callback is null");
222               }
223               // 调用ArkTS的buffer处理回调函数,将图片arrayBuffer传给页面做显示或保存
224               napi_call_function(env, nullptr, callback, 1, &arrayBuffer, &retVal);
225               // 清理内存
226               free(data); // 释放在异步工作中分配的内存
227           },
228           copyBuffer, &work);
229
230       // 错误检查:创建异步工作失败时释放内存
231       if (status != napi_ok) {
232           OH_LOG_ERROR(LOG_APP, "Failed to create async work");
233           free(copyBuffer); // 释放分配的内存
234           return;
235       }
236       napi_queue_async_work_with_qos(env_, work, napi_qos_user_initiated);
237   }
238
239   // 保存ArkTS侧传入的buffer处理回调函数
240   static napi_value SetBufferCb(napi_env env, napi_callback_info info) {
241       OH_LOG_INFO(LOG_APP, "SetBufferCb start");
242       napi_value result;
243       napi_get_undefined(env, &result);
244
245       napi_value argValue[1] = {nullptr};
246       size_t argCount = 1;
247       napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr);
248
249       env_ = env;
250       napi_create_reference(env, argValue[0], 1, &bufferCbRef_);
251       if (bufferCbRef_) {
252           OH_LOG_INFO(LOG_APP, "SetBufferCb callbackRef is full");
253       } else {
254           OH_LOG_ERROR(LOG_APP, "SetBufferCb callbackRef is null");
255       }
256       // 注册ArkTS侧buffer回调到NAPI层
257       ndkCamera_->RegisterBufferCb((void *)BufferCb);
258       return result;
259   }
260   ```
261
262   ArkTS侧buffer处理参考示例代码:
263
264   ```ts
265   /*
266    * Copyright (c) 2024 Huawei Device Co., Ltd.
267    * Licensed under the Apache License, Version 2.0 (the 'License');
268    * you may not use this file except in compliance with the License.
269    * You may obtain a copy of the License at
270    *
271    *     http://www.apache.org/licenses/LICENSE-2.0
272    *
273    * Unless required by applicable law or agreed to in writing, software
274    * distributed under the License is distributed on an 'AS IS' BASIS,
275    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
276    * See the License for the specific language governing permissions and
277    * limitations under the License.
278    */
279
280   import { image } from '@kit.ImageKit';
281   import { photoAccessHelper } from '@kit.MediaLibraryKit';
282   import { fileIo } from '@kit.CoreFileKit';
283   import { BusinessError } from '@kit.BasicServicesKit';
284   import cameraDemo from 'libentry.so';
285
286   interface PhotoSettings {
287     quality: number, // Photo quality
288     rotation: number, // Photo direction
289     mirror: boolean, // Mirror Enable
290     latitude: number, // geographic location
291     longitude: number, // geographic location
292     altitude: number // geographic location
293   };
294
295   @Entry
296   @Component
297   struct Index {
298     private mXComponentController: XComponentController = new XComponentController();
299     private surfaceId = '';
300     private file: fileIo.File | undefined;
301     @State imageWidth: number = 1920;
302     @State imageHeight: number = 1080;
303     @State showImage: boolean = false;
304     @State curPixelMap: image.PixelMap | undefined = undefined;
305     photoSettings: PhotoSettings = {
306       quality: 0,
307       rotation: 0,
308       mirror: false,
309       latitude: 12.9698,
310       longitude: 77.7500,
311       altitude: 1000
312     };
313     // ArrayBuffer处理回调函数
314     photoBufferCallback: (arrayBuffer: ArrayBuffer) => void = (arrayBuffer: ArrayBuffer) => {
315       console.info('photoBufferCallback')
316       // 处理方式一:创建PixelMap显示图片
317       let imageSource = image.createImageSource(arrayBuffer);
318       imageSource.createPixelMap((err: BusinessError, data: image.PixelMap) => {
319         this.curPixelMap = data;
320         this.showImage = true;
321       })
322       // 处理方式二:通过安全控件写文件保存图片
323       fileIo.write(this.file?.fd, arrayBuffer)
324         .then(() => {
325           console.info('file write OK');
326           // 关闭文件
327           fileIo.close(this.file);
328         }).catch(() => {
329         console.error('file write failed');
330       })
331     }
332
333     onPageShow(): void {
334     }
335
336     onPageHide(): void {
337       cameraDemo.releaseCamera();
338     }
339
340     build() {
341       Column() {
342         Column() {
343           if (!this.showImage) {
344             XComponent({
345               id: 'componentId',
346               type: 'surface',
347               controller: this.mXComponentController
348             })
349               .onLoad(async () => {
350                 console.info('onLoad is called');
351                 this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
352                 let surfaceRect: SurfaceRect = {
353                   surfaceWidth: this.imageHeight,
354                   surfaceHeight: this.imageWidth
355                 };
356                 this.mXComponentController.setXComponentSurfaceRect(surfaceRect);
357                 console.info(`onLoad surfaceId: ${this.surfaceId}`);
358                 // 调用NDK接口初始化相机
359                 await cameraDemo.initCamera(this.surfaceId);
360                 // 注册ArkTS侧buffer处理回调
361                 cameraDemo.setBufferCb(this.photoBufferCallback);
362               })// The width and height of the surface are opposite to those of the XComponent.
363               .width(px2vp(this.imageHeight))
364               .height(px2vp(this.imageWidth))
365           }
366
367           if (this.showImage) {
368             // 显示拍照得到的图片
369             Image(this.curPixelMap)
370               .width(px2vp(this.imageHeight))
371               .height(px2vp(this.imageWidth))
372           }
373
374         }
375         .justifyContent(FlexAlign.Center)
376         .height('80%')
377
378           // 安全控件,用来保存媒体资源
379           SaveButton({text:SaveDescription.SAVE_IMAGE}).onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
380             if (result == SaveButtonOnClickResult.SUCCESS) {
381               try {
382                 const context = getContext(this);
383                 let helper = photoAccessHelper.getPhotoAccessHelper(context);
384                 // onClick触发后10秒内通过createAsset接口创建图片文件,10秒后createAsset权限收回。
385                 let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
386                 console.error('uri:' + uri);
387                 // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制
388                 this.file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
389                 // 调用NDK接口拍照,触发PhotoAvailable回调
390                 cameraDemo.takePictureWithSettings(this.photoSettings);
391               } catch (error) {
392                 console.error("error is " + JSON.stringify(error));
393               }
394             }
395           })
396
397           Text('NdkPhotoAvailableDemo')
398             .fontSize(30)
399       }
400       .justifyContent(FlexAlign.End)
401       .height('100%')
402       .width('100%')
403     }
404   }
405   ```
406
4076. 创建拍照类型会话,参考[会话管理(C/C++)](./native-camera-session-management.md),开启会话,准备拍照。
408
409   ```c++
410   // 创建相机会话
411   Camera_CaptureSession* captureSession = nullptr;
412   Camera_ErrorCode ret = OH_CameraManager_CreateCaptureSession(cameraManager, &captureSession);
413   if (captureSession == nullptr || ret != CAMERA_OK) {
414       OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCaptureSession failed.");
415   }
416   // 设置会话模式为拍照模式
417   Camera_SceneMode sceneMode = NORMAL_PHOTO;
418   ret = OH_CaptureSession_SetSessionMode(captureSession, sceneMode);
419   // 配置会话开始
420   ret = OH_CaptureSession_BeginConfig(captureSession);
421   ```
422
4237. 配置拍照参数(可选)。
424   配置相机的参数可以调整拍照的一些功能,包括闪光灯、变焦、焦距等。
425
426   ```c++
427   // 判断设备是否支持闪光灯
428    Camera_FlashMode flashMode = FLASH_MODE_AUTO;
429    bool hasFlash = false;
430    ret = OH_CaptureSession_HasFlash(captureSession, &hasFlash);
431    if (ret != CAMERA_OK) {
432        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_HasFlash failed.");
433    }
434    if (hasFlash) {
435        OH_LOG_INFO(LOG_APP, "hasFlash success");
436    } else {
437        OH_LOG_ERROR(LOG_APP, "hasFlash fail");
438    }
439    // 检测闪光灯模式是否支持
440    bool isSupported = false;
441    ret = OH_CaptureSession_IsFlashModeSupported(captureSession, flashMode, &isSupported);
442    if (ret != CAMERA_OK) {
443        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFlashModeSupported failed.");
444    }
445    if (isSupported) {
446        OH_LOG_INFO(LOG_APP, "isFlashModeSupported success");
447        // 设置闪光灯模式
448        ret = OH_CaptureSession_SetFlashMode(captureSession, flashMode);
449        if (ret == CAMERA_OK) {
450            OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetFlashMode success.");
451        } else {
452            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFlashMode failed. %{public}d ", ret);
453        }
454        // 获取当前设备的闪光灯模式
455        ret = OH_CaptureSession_GetFlashMode(captureSession, &flashMode);
456        if (ret == CAMERA_OK) {
457            OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFlashMode success. flashMode:%{public}d ", flashMode);
458        } else {
459            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFlashMode failed. %d ", ret);
460        }
461    } else {
462        OH_LOG_ERROR(LOG_APP, "isFlashModeSupported fail");
463    }
464
465    // 判断是否支持连续自动变焦模式
466    Camera_FocusMode focusMode = FOCUS_MODE_CONTINUOUS_AUTO;
467    bool isFocusModeSupported = false;
468    ret = OH_CaptureSession_IsFocusModeSupported(captureSession, focusMode, &isFocusModeSupported);
469    if (ret != CAMERA_OK) {
470        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFocusModeSupported failed.");
471    }
472    if (isFocusModeSupported) {
473        OH_LOG_INFO(LOG_APP, "isFocusModeSupported success");
474        ret = OH_CaptureSession_SetFocusMode(captureSession, focusMode);
475        if (ret != CAMERA_OK) {
476            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFocusMode failed. %{public}d ", ret);
477        }
478        ret = OH_CaptureSession_GetFocusMode(captureSession, &focusMode);
479        if (ret == CAMERA_OK) {
480            OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFocusMode success. focusMode%{public}d ", focusMode);
481        } else {
482            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFocusMode failed. %d ", ret);
483        }
484    } else {
485        OH_LOG_ERROR(LOG_APP, "isFocusModeSupported fail");
486    }
487
488    // 获取相机支持的可变焦距比范围
489    float minZoom;
490    float maxZoom;
491    ret = OH_CaptureSession_GetZoomRatioRange(captureSession, &minZoom, &maxZoom);
492    if (ret != CAMERA_OK) {
493        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatioRange failed.");
494    } else {
495        OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatioRange success. minZoom: %{public}f, maxZoom:%{public}f",
496            minZoom, maxZoom);
497    }
498    // 设置变焦
499    ret = OH_CaptureSession_SetZoomRatio(captureSession, maxZoom);
500    if (ret == CAMERA_OK) {
501        OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetZoomRatio success.");
502    } else {
503        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetZoomRatio failed. %{public}d ", ret);
504    }
505    // 获取当前设备的变焦值
506    ret = OH_CaptureSession_GetZoomRatio(captureSession, &maxZoom);
507    if (ret == CAMERA_OK) {
508        OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatio success. zoom:%{public}f ", maxZoom);
509    } else {
510        OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatio failed. %{public}d ", ret);
511    }
512   ```
513
5148. 触发拍照。
515
516    通过OH_PhotoOutput_Capture()方法,执行拍照任务。
517
518     ```c++
519      ret = OH_PhotoOutput_Capture(photoOutput);
520      if (ret == CAMERA_OK) {
521          OH_LOG_INFO(LOG_APP, "OH_PhotoOutput_Capture success ");
522      } else {
523          OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_Capture failed. %d ", ret);
524      }
525     ```
526
527## 状态监听
528
529在相机应用开发过程中,可以随时监听拍照输出流状态,包括拍照流开始、拍照帧的开始与结束、拍照输出流的错误。
530
531- 通过注册固定的onFrameStart回调函数获取监听拍照开始结果,photoOutput创建成功时即可监听,拍照第一次曝光时触发。
532
533  ```c++
534    ret = OH_PhotoOutput_RegisterCallback(photoOutput, GetPhotoOutputListener());
535    if (ret != CAMERA_OK) {
536        OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_RegisterCallback failed.");
537    }
538  ```
539  ```c++
540    void PhotoOutputOnFrameStart(Camera_PhotoOutput* photoOutput)
541    {
542        OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameStart");
543    }
544    void PhotoOutputOnFrameShutter(Camera_PhotoOutput* photoOutput, Camera_FrameShutterInfo* info)
545    {
546        OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameShutter");
547    }
548    PhotoOutput_Callbacks* GetPhotoOutputListener()
549    {
550        static PhotoOutput_Callbacks photoOutputListener = {
551            .onFrameStart = PhotoOutputOnFrameStart,
552            .onFrameShutter = PhotoOutputOnFrameShutter,
553            .onFrameEnd = PhotoOutputOnFrameEnd,
554            .onError = PhotoOutputOnError
555        };
556        return &photoOutputListener;
557    }
558  ```
559
560- 通过注册固定的onFrameEnd回调函数获取监听拍照结束结果,photoOutput创建成功时即可监听。
561
562  ```c++
563    void PhotoOutputOnFrameEnd(Camera_PhotoOutput* photoOutput, int32_t frameCount)
564    {
565        OH_LOG_INFO(LOG_APP, "PhotoOutput frameCount = %{public}d", frameCount);
566    }
567  ```
568
569- 通过注册固定的onError回调函数获取监听拍照输出流的错误结果。callback返回拍照输出接口使用错误时的对应错误码,错误码类型参见[Camera_ErrorCode](../../reference/apis-camera-kit/_o_h___camera.md#camera_errorcode-1)。
570
571  ```c++
572    void PhotoOutputOnError(Camera_PhotoOutput* photoOutput, Camera_ErrorCode errorCode)
573    {
574        OH_LOG_INFO(LOG_APP, "PhotoOutput errorCode = %{public}d", errorCode);
575    }
576  ```