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 ```