1# 拍照实践(C/C++) 2 3在开发相机应用时,需要先参考开发准备[申请相关权限](camera-preparation.md)。 4 5当前示例提供完整的拍照流程及其接口调用顺序的介绍。对于单个流程(如设备输入、会话管理、拍照)的介绍请参考[相机开发指导(Native)](camera-preparation.md)的具体章节。 6 7## 开发流程 8 9在获取到相机支持的输出流能力后,开始创建拍照流,开发流程如下。 10 11 12 13## 完整示例 14 151. 在CMake脚本中链接相关动态库。 16 ```txt 17 target_link_libraries(entry PUBLIC 18 libace_napi.z.so 19 libhilog_ndk.z.so 20 libnative_buffer.so 21 libohcamera.so 22 libohimage.so 23 libohfileuri.so 24 ) 25 ``` 262. 创建头文件ndk_camera.h。 27 ```c++ 28 #include "ohcamera/camera.h" 29 #include "ohcamera/camera_input.h" 30 #include "ohcamera/capture_session.h" 31 #include "ohcamera/photo_output.h" 32 #include "ohcamera/preview_output.h" 33 #include "ohcamera/video_output.h" 34 #include "ohcamera/camera_manager.h" 35 36 class NDKCamera { 37 public: 38 ~NDKCamera(); 39 NDKCamera(char* previewId); 40 Camera_ErrorCode RegisterBufferCb(void* cb); 41 }; 42 ``` 43 443. cpp侧导入NDK接口,并根据传入的SurfaceId进行拍照。 45 ```c++ 46 #include "hilog/log.h" 47 #include "ndk_camera.h" 48 49 void CaptureSessionOnFocusStateChange(Camera_CaptureSession* session, Camera_FocusState focusState) 50 { 51 OH_LOG_INFO(LOG_APP, "CaptureSessionOnFocusStateChange"); 52 } 53 54 void CaptureSessionOnError(Camera_CaptureSession* session, Camera_ErrorCode errorCode) 55 { 56 OH_LOG_INFO(LOG_APP, "CaptureSessionOnError = %{public}d", errorCode); 57 } 58 59 CaptureSession_Callbacks* GetCaptureSessionRegister(void) 60 { 61 static CaptureSession_Callbacks captureSessionCallbacks = { 62 .onFocusStateChange = CaptureSessionOnFocusStateChange, 63 .onError = CaptureSessionOnError 64 }; 65 return &captureSessionCallbacks; 66 } 67 68 void PreviewOutputOnFrameStart(Camera_PreviewOutput* previewOutput) 69 { 70 OH_LOG_INFO(LOG_APP, "PreviewOutputOnFrameStart"); 71 } 72 73 void PreviewOutputOnFrameEnd(Camera_PreviewOutput* previewOutput, int32_t frameCount) 74 { 75 OH_LOG_INFO(LOG_APP, "PreviewOutputOnFrameEnd = %{public}d", frameCount); 76 } 77 78 void PreviewOutputOnError(Camera_PreviewOutput* previewOutput, Camera_ErrorCode errorCode) 79 { 80 OH_LOG_INFO(LOG_APP, "PreviewOutputOnError = %{public}d", errorCode); 81 } 82 83 PreviewOutput_Callbacks* GetPreviewOutputListener(void) 84 { 85 static PreviewOutput_Callbacks previewOutputListener = { 86 .onFrameStart = PreviewOutputOnFrameStart, 87 .onFrameEnd = PreviewOutputOnFrameEnd, 88 .onError = PreviewOutputOnError 89 }; 90 return &previewOutputListener; 91 } 92 93 void OnCameraInputError(const Camera_Input* cameraInput, Camera_ErrorCode errorCode) 94 { 95 OH_LOG_INFO(LOG_APP, "OnCameraInput errorCode = %{public}d", errorCode); 96 } 97 98 CameraInput_Callbacks* GetCameraInputListener(void) 99 { 100 static CameraInput_Callbacks cameraInputCallbacks = { 101 .onError = OnCameraInputError 102 }; 103 return &cameraInputCallbacks; 104 } 105 106 void CameraManagerStatusCallback(Camera_Manager* cameraManager, Camera_StatusInfo* status) 107 { 108 OH_LOG_INFO(LOG_APP, "CameraManagerStatusCallback is called"); 109 } 110 111 CameraManager_Callbacks* GetCameraManagerListener() 112 { 113 static CameraManager_Callbacks cameraManagerListener = { 114 .onCameraStatus = CameraManagerStatusCallback 115 }; 116 return &cameraManagerListener; 117 } 118 119 static void* bufferCb = nullptr; 120 Camera_ErrorCode NDKCamera::RegisterBufferCb(void* cb) { 121 OH_LOG_INFO(LOG_APP, " RegisterBufferCb start"); 122 if (cb == nullptr) { 123 OH_LOG_INFO(LOG_APP, " RegisterBufferCb invalid error"); 124 return CAMERA_INVALID_ARGUMENT; 125 } 126 bufferCb = cb; 127 128 return CAMERA_OK; 129 } 130 void OnPhotoAvailable(Camera_PhotoOutput* photoOutput, OH_PhotoNative* photo) { 131 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable start!"); 132 OH_ImageNative* imageNative; 133 Camera_ErrorCode errCode = OH_PhotoNative_GetMainImage(photo, &imageNative); 134 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable errCode:%{public}d imageNative:%{public}p", errCode, imageNative); 135 // 读取 OH_ImageNative 的 size 属性。 136 Image_Size size; 137 Image_ErrorCode imageErr = OH_ImageNative_GetImageSize(imageNative, &size); 138 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d width:%{public}d height:%{public}d", imageErr, 139 size.width, size.height); 140 // 读取 OH_ImageNative 的组件列表的元素个数。 141 size_t componentTypeSize = 0; 142 imageErr = OH_ImageNative_GetComponentTypes(imageNative, nullptr, &componentTypeSize); 143 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d componentTypeSize:%{public}zu", imageErr, 144 componentTypeSize); 145 // 读取 OH_ImageNative 的组件列表。 146 uint32_t* components = new uint32_t[componentTypeSize]; 147 imageErr = OH_ImageNative_GetComponentTypes(imageNative, &components, &componentTypeSize); 148 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_ImageNative_GetComponentTypes imageErr:%{public}d", imageErr); 149 // 读取 OH_ImageNative 的第一个组件所对应的缓冲区对象。 150 OH_NativeBuffer* nativeBuffer = nullptr; 151 imageErr = OH_ImageNative_GetByteBuffer(imageNative, components[0], &nativeBuffer); 152 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_ImageNative_GetByteBuffer imageErr:%{public}d", imageErr); 153 // 读取 OH_ImageNative 的第一个组件所对应的缓冲区大小。 154 size_t nativeBufferSize = 0; 155 imageErr = OH_ImageNative_GetBufferSize(imageNative, components[0], &nativeBufferSize); 156 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d nativeBufferSize:%{public}zu", imageErr, 157 nativeBufferSize); 158 // 读取 OH_ImageNative 的第一个组件所对应的像素行宽。 159 int32_t rowStride = 0; 160 imageErr = OH_ImageNative_GetRowStride(imageNative, components[0], &rowStride); 161 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d rowStride:%{public}d", imageErr, rowStride); 162 // 读取 OH_ImageNative 的第一个组件所对应的像素大小。 163 int32_t pixelStride = 0; 164 imageErr = OH_ImageNative_GetPixelStride(imageNative, components[0], &pixelStride); 165 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d pixelStride:%{public}d", imageErr, pixelStride); 166 // 将ION内存映射到进程空间。 167 void* virAddr = nullptr; // 指向映射内存的虚拟地址,解除映射后这个指针将不再有效。 168 int32_t ret = OH_NativeBuffer_Map(nativeBuffer, &virAddr); // 映射后通过第二个参数virAddr返回内存的首地址。 169 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_NativeBuffer_Map err:%{public}d", ret); 170 // 通过回调函数,将处理完的buffer传给ArkTS侧做显示或通过安全控件写文件保存,参考拍照(C/C++)开发指导。 171 auto cb = (void (*)(void *, size_t))(bufferCb); 172 cb(virAddr, nativeBufferSize); 173 // 在处理完之后,解除映射并释放缓冲区。 174 ret = OH_NativeBuffer_Unmap(nativeBuffer); 175 if (ret != 0) { 176 OH_LOG_ERROR(LOG_APP, "OnPhotoAvailable OH_NativeBuffer_Unmap error:%{public}d", ret); 177 } 178 } 179 180 NDKCamera::NDKCamera(char* previewId) 181 { 182 Camera_Manager* cameraManager = nullptr; 183 Camera_Device* cameras = nullptr; 184 Camera_CaptureSession* captureSession = nullptr; 185 Camera_OutputCapability* cameraOutputCapability = nullptr; 186 const Camera_Profile* previewProfile = nullptr; 187 const Camera_Profile* photoProfile = nullptr; 188 Camera_PreviewOutput* previewOutput = nullptr; 189 Camera_PhotoOutput* photoOutput = nullptr; 190 Camera_Input* cameraInput = nullptr; 191 uint32_t size = 0; 192 uint32_t cameraDeviceIndex = 0; 193 char* previewSurfaceId = previewId; 194 // 创建CameraManager对象。 195 Camera_ErrorCode ret = OH_Camera_GetCameraManager(&cameraManager); 196 if (cameraManager == nullptr || ret != CAMERA_OK) { 197 OH_LOG_ERROR(LOG_APP, "OH_Camera_GetCameraMananger failed."); 198 return; 199 } 200 // 监听相机状态变化。 201 ret = OH_CameraManager_RegisterCallback(cameraManager, GetCameraManagerListener()); 202 if (ret != CAMERA_OK) { 203 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_RegisterCallback failed."); 204 } 205 206 // 获取相机列表。 207 ret = OH_CameraManager_GetSupportedCameras(cameraManager, &cameras, &size); 208 if (cameras == nullptr || size < 0 || ret != CAMERA_OK) { 209 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameras failed."); 210 return; 211 } 212 213 // 创建相机输入流。 214 ret = OH_CameraManager_CreateCameraInput(cameraManager, &cameras[cameraDeviceIndex], &cameraInput); 215 if (cameraInput == nullptr || ret != CAMERA_OK) { 216 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCameraInput failed."); 217 return; 218 } 219 220 // 监听cameraInput错误信息。 221 ret = OH_CameraInput_RegisterCallback(cameraInput, GetCameraInputListener()); 222 if (ret != CAMERA_OK) { 223 OH_LOG_ERROR(LOG_APP, "OH_CameraInput_RegisterCallback failed."); 224 return; 225 } 226 227 // 打开相机。 228 ret = OH_CameraInput_Open(cameraInput); 229 if (ret != CAMERA_OK) { 230 OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Open failed."); 231 return; 232 } 233 234 // 获取相机设备支持的输出流能力。 235 ret = OH_CameraManager_GetSupportedCameraOutputCapability(cameraManager, &cameras[cameraDeviceIndex], 236 &cameraOutputCapability); 237 if (cameraOutputCapability == nullptr || ret != CAMERA_OK) { 238 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameraOutputCapability failed."); 239 return; 240 } 241 242 if (cameraOutputCapability->previewProfiles == nullptr) { 243 OH_LOG_ERROR(LOG_APP, "previewProfiles == null"); 244 return; 245 } 246 // 根据所需从cameraOutputCapability->previewProfiles中选择合适的预览分辨率 247 previewProfile = cameraOutputCapability->previewProfiles[0]; 248 249 if (cameraOutputCapability->photoProfiles == nullptr) { 250 OH_LOG_ERROR(LOG_APP, "photoProfiles == null"); 251 return; 252 } 253 // 根据所需从cameraOutputCapability->photoProfiles中选择合适的拍照分辨率 254 photoProfile = cameraOutputCapability->photoProfiles[0]; 255 256 // 创建预览输出流,其中参数 previewSurfaceId 参考上文 XComponent 组件,预览流为XComponent组件提供的surface。 257 ret = OH_CameraManager_CreatePreviewOutput(cameraManager, previewProfile, previewSurfaceId, &previewOutput); 258 if (previewProfile == nullptr || previewOutput == nullptr || ret != CAMERA_OK) { 259 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput failed."); 260 return; 261 } 262 263 // 监听预览输出错误信息。 264 ret = OH_PreviewOutput_RegisterCallback(previewOutput, GetPreviewOutputListener()); 265 if (ret != CAMERA_OK) { 266 OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_RegisterCallback failed."); 267 } 268 269 // 创建拍照输出流。 270 ret = OH_CameraManager_CreatePhotoOutputWithoutSurface(cameraManager, photoProfile, &photoOutput); 271 272 // 监听单端式拍照回调。 273 ret = OH_PhotoOutput_RegisterPhotoAvailableCallback(photoOutput, OnPhotoAvailable); 274 275 //创建会话。 276 ret = OH_CameraManager_CreateCaptureSession(cameraManager, &captureSession); 277 if (captureSession == nullptr || ret != CAMERA_OK) { 278 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCaptureSession failed."); 279 return; 280 } 281 282 // 监听session错误信息。 283 ret = OH_CaptureSession_RegisterCallback(captureSession, GetCaptureSessionRegister()); 284 if (ret != CAMERA_OK) { 285 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_RegisterCallback failed."); 286 } 287 288 // 开始配置会话。 289 ret = OH_CaptureSession_BeginConfig(captureSession); 290 if (ret != CAMERA_OK) { 291 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed."); 292 return; 293 } 294 295 // 向会话中添加相机输入流。 296 ret = OH_CaptureSession_AddInput(captureSession, cameraInput); 297 if (ret != CAMERA_OK) { 298 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddInput failed."); 299 return; 300 } 301 302 // 向会话中添加预览输出流。 303 ret = OH_CaptureSession_AddPreviewOutput(captureSession, previewOutput); 304 if (ret != CAMERA_OK) { 305 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPreviewOutput failed."); 306 return; 307 } 308 309 // 向会话中添加拍照输出流。 310 ret = OH_CaptureSession_AddPhotoOutput(captureSession, photoOutput); 311 if (ret != CAMERA_OK) { 312 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPhotoOutput failed."); 313 return; 314 } 315 316 // 提交会话配置。 317 ret = OH_CaptureSession_CommitConfig(captureSession); 318 if (ret != CAMERA_OK) { 319 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed."); 320 return; 321 } 322 323 // 启动会话。 324 ret = OH_CaptureSession_Start(captureSession); 325 if (ret != CAMERA_OK) { 326 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed."); 327 return; 328 } 329 330 // 判断设备是否支持闪光灯。 331 Camera_FlashMode flashMode = FLASH_MODE_AUTO; 332 bool hasFlash = false; 333 ret = OH_CaptureSession_HasFlash(captureSession, &hasFlash); 334 if (ret != CAMERA_OK) { 335 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_HasFlash failed."); 336 } 337 if (hasFlash) { 338 OH_LOG_INFO(LOG_APP, "hasFlash success"); 339 } else { 340 OH_LOG_ERROR(LOG_APP, "hasFlash fail"); 341 } 342 343 // 检测闪光灯模式是否支持。 344 bool isSupported = false; 345 ret = OH_CaptureSession_IsFlashModeSupported(captureSession, flashMode, &isSupported); 346 if (ret != CAMERA_OK) { 347 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFlashModeSupported failed."); 348 } 349 if (isSupported) { 350 OH_LOG_INFO(LOG_APP, "isFlashModeSupported success"); 351 352 // 设置闪光灯模式。 353 ret = OH_CaptureSession_SetFlashMode(captureSession, flashMode); 354 if (ret == CAMERA_OK) { 355 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetFlashMode success."); 356 } else { 357 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFlashMode failed. %{public}d ", ret); 358 } 359 360 // 获取当前设备的闪光灯模式。 361 ret = OH_CaptureSession_GetFlashMode(captureSession, &flashMode); 362 if (ret == CAMERA_OK) { 363 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFlashMode success. flashMode:%{public}d ", flashMode); 364 } else { 365 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFlashMode failed. %d ", ret); 366 } 367 } else { 368 OH_LOG_ERROR(LOG_APP, "isFlashModeSupported fail"); 369 } 370 371 // 判断是否支持连续自动变焦模式。 372 Camera_FocusMode focusMode = FOCUS_MODE_CONTINUOUS_AUTO; 373 bool isFocusModeSupported = false; 374 ret = OH_CaptureSession_IsFocusModeSupported(captureSession, focusMode, &isFocusModeSupported); 375 if (ret != CAMERA_OK) { 376 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFocusModeSupported failed."); 377 } 378 if (isFocusModeSupported) { 379 OH_LOG_INFO(LOG_APP, "isFocusModeSupported success"); 380 ret = OH_CaptureSession_SetFocusMode(captureSession, focusMode); 381 if (ret != CAMERA_OK) { 382 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFocusMode failed. %{public}d ", ret); 383 } 384 ret = OH_CaptureSession_GetFocusMode(captureSession, &focusMode); 385 if (ret == CAMERA_OK) { 386 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFocusMode success. focusMode%{public}d ", focusMode); 387 } else { 388 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFocusMode failed. %d ", ret); 389 } 390 } else { 391 OH_LOG_ERROR(LOG_APP, "isFocusModeSupported fail"); 392 } 393 394 // 获取相机支持的可变焦距比范围。 395 float minZoom; 396 float maxZoom; 397 ret = OH_CaptureSession_GetZoomRatioRange(captureSession, &minZoom, &maxZoom); 398 if (ret != CAMERA_OK) { 399 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatioRange failed."); 400 } else { 401 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatioRange success. minZoom: %{public}f, maxZoom:%{public}f", 402 minZoom, maxZoom); 403 } 404 405 // 设置变焦。 406 ret = OH_CaptureSession_SetZoomRatio(captureSession, maxZoom); 407 if (ret == CAMERA_OK) { 408 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetZoomRatio success."); 409 } else { 410 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetZoomRatio failed. %{public}d ", ret); 411 } 412 413 // 获取当前设备的变焦值。 414 ret = OH_CaptureSession_GetZoomRatio(captureSession, &maxZoom); 415 if (ret == CAMERA_OK) { 416 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatio success. zoom:%{public}f ", maxZoom); 417 } else { 418 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatio failed. %{public}d ", ret); 419 } 420 421 // 无拍照设置进行拍照。 422 ret = OH_PhotoOutput_Capture(photoOutput); 423 if (ret == CAMERA_OK) { 424 OH_LOG_INFO(LOG_APP, "OH_PhotoOutput_Capture success "); 425 } else { 426 OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_Capture failed. %d ", ret); 427 } 428 429 // 停止当前会话。 430 ret = OH_CaptureSession_Stop(captureSession); 431 if (ret == CAMERA_OK) { 432 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Stop success "); 433 } else { 434 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Stop failed. %d ", ret); 435 } 436 437 // 释放相机输入流。 438 ret = OH_CameraInput_Close(cameraInput); 439 if (ret == CAMERA_OK) { 440 OH_LOG_INFO(LOG_APP, "OH_CameraInput_Close success "); 441 } else { 442 OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Close failed. %d ", ret); 443 } 444 445 // 释放预览输出流。 446 ret = OH_PreviewOutput_Release(previewOutput); 447 if (ret == CAMERA_OK) { 448 OH_LOG_INFO(LOG_APP, "OH_PreviewOutput_Release success "); 449 } else { 450 OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_Release failed. %d ", ret); 451 } 452 453 // 释放拍照输出流。 454 ret = OH_PhotoOutput_Release(photoOutput); 455 if (ret == CAMERA_OK) { 456 OH_LOG_INFO(LOG_APP, "OH_PhotoOutput_Release success "); 457 } else { 458 OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_Release failed. %d ", ret); 459 } 460 461 // 释放会话。 462 ret = OH_CaptureSession_Release(captureSession); 463 if (ret == CAMERA_OK) { 464 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Release success "); 465 } else { 466 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Release failed. %d ", ret); 467 } 468 469 // 资源释放。 470 ret = OH_CameraManager_DeleteSupportedCameras(cameraManager, cameras, size); 471 if (ret != CAMERA_OK) { 472 OH_LOG_ERROR(LOG_APP, "Delete Cameras failed."); 473 } else { 474 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_DeleteSupportedCameras. ok"); 475 } 476 ret = OH_CameraManager_DeleteSupportedCameraOutputCapability(cameraManager, cameraOutputCapability); 477 if (ret != CAMERA_OK) { 478 OH_LOG_ERROR(LOG_APP, "Delete Cameras failed."); 479 } else { 480 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_DeleteSupportedCameraOutputCapability. ok"); 481 } 482 ret = OH_Camera_DeleteCameraManager(cameraManager); 483 if (ret != CAMERA_OK) { 484 OH_LOG_ERROR(LOG_APP, "Delete Cameras failed."); 485 } else { 486 OH_LOG_ERROR(LOG_APP, "OH_Camera_DeleteCameraManager. ok"); 487 } 488 } 489 ```