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