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 } 199 // 监听相机状态变化。 200 ret = OH_CameraManager_RegisterCallback(cameraManager, GetCameraManagerListener()); 201 if (ret != CAMERA_OK) { 202 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_RegisterCallback failed."); 203 } 204 205 // 获取相机列表。 206 ret = OH_CameraManager_GetSupportedCameras(cameraManager, &cameras, &size); 207 if (cameras == nullptr || size < 0 || ret != CAMERA_OK) { 208 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameras failed."); 209 } 210 211 // 创建相机输入流。 212 ret = OH_CameraManager_CreateCameraInput(cameraManager, &cameras[cameraDeviceIndex], &cameraInput); 213 if (cameraInput == nullptr || ret != CAMERA_OK) { 214 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCameraInput failed."); 215 } 216 217 // 监听cameraInput错误信息。 218 ret = OH_CameraInput_RegisterCallback(cameraInput, GetCameraInputListener()); 219 if (ret != CAMERA_OK) { 220 OH_LOG_ERROR(LOG_APP, "OH_CameraInput_RegisterCallback failed."); 221 } 222 223 // 打开相机。 224 ret = OH_CameraInput_Open(cameraInput); 225 if (ret != CAMERA_OK) { 226 OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Open failed."); 227 } 228 229 // 获取相机设备支持的输出流能力。 230 ret = OH_CameraManager_GetSupportedCameraOutputCapability(cameraManager, &cameras[cameraDeviceIndex], 231 &cameraOutputCapability); 232 if (cameraOutputCapability == nullptr || ret != CAMERA_OK) { 233 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameraOutputCapability failed."); 234 } 235 236 if (cameraOutputCapability->previewProfilesSize < 0) { 237 OH_LOG_ERROR(LOG_APP, "previewProfilesSize == null"); 238 } 239 previewProfile = cameraOutputCapability->previewProfiles[0]; 240 241 if (cameraOutputCapability->photoProfilesSize < 0) { 242 OH_LOG_ERROR(LOG_APP, "photoProfilesSize == null"); 243 } 244 photoProfile = cameraOutputCapability->photoProfiles[0]; 245 246 247 // 创建预览输出流,其中参数 previewSurfaceId 参考上文 XComponent 组件,预览流为XComponent组件提供的surface。 248 ret = OH_CameraManager_CreatePreviewOutput(cameraManager, previewProfile, previewSurfaceId, &previewOutput); 249 if (previewProfile == nullptr || previewOutput == nullptr || ret != CAMERA_OK) { 250 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput failed."); 251 } 252 253 // 监听预览输出错误信息。 254 ret = OH_PreviewOutput_RegisterCallback(previewOutput, GetPreviewOutputListener()); 255 if (ret != CAMERA_OK) { 256 OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_RegisterCallback failed."); 257 } 258 259 // 创建拍照输出流。 260 ret = OH_CameraManager_CreatePhotoOutputWithoutSurface(cameraManager, photoProfile, &photoOutput); 261 262 // 监听单端式拍照回调 263 ret = OH_PhotoOutput_RegisterPhotoAvailableCallback(photoOutput, OnPhotoAvailable); 264 265 //创建会话。 266 ret = OH_CameraManager_CreateCaptureSession(cameraManager, &captureSession); 267 if (captureSession == nullptr || ret != CAMERA_OK) { 268 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCaptureSession failed."); 269 } 270 271 // 监听session错误信息。 272 ret = OH_CaptureSession_RegisterCallback(captureSession, GetCaptureSessionRegister()); 273 if (ret != CAMERA_OK) { 274 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_RegisterCallback failed."); 275 } 276 277 // 开始配置会话。 278 ret = OH_CaptureSession_BeginConfig(captureSession); 279 if (ret != CAMERA_OK) { 280 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed."); 281 } 282 283 // 向会话中添加相机输入流。 284 ret = OH_CaptureSession_AddInput(captureSession, cameraInput); 285 if (ret != CAMERA_OK) { 286 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddInput failed."); 287 } 288 289 // 向会话中添加预览输出流。 290 ret = OH_CaptureSession_AddPreviewOutput(captureSession, previewOutput); 291 if (ret != CAMERA_OK) { 292 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPreviewOutput failed."); 293 } 294 295 // 向会话中添加拍照输出流。 296 ret = OH_CaptureSession_AddPhotoOutput(captureSession, photoOutput); 297 if (ret != CAMERA_OK) { 298 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPhotoOutput failed."); 299 } 300 301 // 提交会话配置。 302 ret = OH_CaptureSession_CommitConfig(captureSession); 303 if (ret != CAMERA_OK) { 304 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed."); 305 } 306 307 // 启动会话。 308 ret = OH_CaptureSession_Start(captureSession); 309 if (ret != CAMERA_OK) { 310 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed."); 311 } 312 313 // 判断设备是否支持闪光灯。 314 Camera_FlashMode flashMode = FLASH_MODE_AUTO; 315 bool hasFlash = false; 316 ret = OH_CaptureSession_HasFlash(captureSession, &hasFlash); 317 if (ret != CAMERA_OK) { 318 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_HasFlash failed."); 319 } 320 if (hasFlash) { 321 OH_LOG_INFO(LOG_APP, "hasFlash success"); 322 } else { 323 OH_LOG_ERROR(LOG_APP, "hasFlash fail"); 324 } 325 // 检测闪光灯模式是否支持。 326 bool isSupported = false; 327 ret = OH_CaptureSession_IsFlashModeSupported(captureSession, flashMode, &isSupported); 328 if (ret != CAMERA_OK) { 329 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFlashModeSupported failed."); 330 } 331 if (isSupported) { 332 OH_LOG_INFO(LOG_APP, "isFlashModeSupported success"); 333 // 设置闪光灯模式。 334 ret = OH_CaptureSession_SetFlashMode(captureSession, flashMode); 335 if (ret == CAMERA_OK) { 336 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetFlashMode success."); 337 } else { 338 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFlashMode failed. %{public}d ", ret); 339 } 340 // 获取当前设备的闪光灯模式。 341 ret = OH_CaptureSession_GetFlashMode(captureSession, &flashMode); 342 if (ret == CAMERA_OK) { 343 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFlashMode success. flashMode:%{public}d ", flashMode); 344 } else { 345 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFlashMode failed. %d ", ret); 346 } 347 } else { 348 OH_LOG_ERROR(LOG_APP, "isFlashModeSupported fail"); 349 } 350 351 // 判断是否支持连续自动变焦模式。 352 Camera_FocusMode focusMode = FOCUS_MODE_CONTINUOUS_AUTO; 353 bool isFocusModeSupported = false; 354 ret = OH_CaptureSession_IsFocusModeSupported(captureSession, focusMode, &isFocusModeSupported); 355 if (ret != CAMERA_OK) { 356 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFocusModeSupported failed."); 357 } 358 if (isFocusModeSupported) { 359 OH_LOG_INFO(LOG_APP, "isFocusModeSupported success"); 360 ret = OH_CaptureSession_SetFocusMode(captureSession, focusMode); 361 if (ret != CAMERA_OK) { 362 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFocusMode failed. %{public}d ", ret); 363 } 364 ret = OH_CaptureSession_GetFocusMode(captureSession, &focusMode); 365 if (ret == CAMERA_OK) { 366 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetFocusMode success. focusMode%{public}d ", focusMode); 367 } else { 368 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetFocusMode failed. %d ", ret); 369 } 370 } else { 371 OH_LOG_ERROR(LOG_APP, "isFocusModeSupported fail"); 372 } 373 374 // 获取相机支持的可变焦距比范围。 375 float minZoom; 376 float maxZoom; 377 ret = OH_CaptureSession_GetZoomRatioRange(captureSession, &minZoom, &maxZoom); 378 if (ret != CAMERA_OK) { 379 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatioRange failed."); 380 } else { 381 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatioRange success. minZoom: %{public}f, maxZoom:%{public}f", 382 minZoom, maxZoom); 383 } 384 385 // 设置变焦。 386 ret = OH_CaptureSession_SetZoomRatio(captureSession, maxZoom); 387 if (ret == CAMERA_OK) { 388 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetZoomRatio success."); 389 } else { 390 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetZoomRatio failed. %{public}d ", ret); 391 } 392 393 // 获取当前设备的变焦值。 394 ret = OH_CaptureSession_GetZoomRatio(captureSession, &maxZoom); 395 if (ret == CAMERA_OK) { 396 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatio success. zoom:%{public}f ", maxZoom); 397 } else { 398 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatio failed. %{public}d ", ret); 399 } 400 401 // 无拍照设置进行拍照。 402 ret = OH_PhotoOutput_Capture(photoOutput); 403 if (ret == CAMERA_OK) { 404 OH_LOG_INFO(LOG_APP, "OH_PhotoOutput_Capture success "); 405 } else { 406 OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_Capture failed. %d ", ret); 407 } 408 409 // 停止当前会话。 410 ret = OH_CaptureSession_Stop(captureSession); 411 if (ret == CAMERA_OK) { 412 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Stop success "); 413 } else { 414 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Stop failed. %d ", ret); 415 } 416 417 // 释放相机输入流。 418 ret = OH_CameraInput_Close(cameraInput); 419 if (ret == CAMERA_OK) { 420 OH_LOG_INFO(LOG_APP, "OH_CameraInput_Close success "); 421 } else { 422 OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Close failed. %d ", ret); 423 } 424 425 // 释放预览输出流。 426 ret = OH_PreviewOutput_Release(previewOutput); 427 if (ret == CAMERA_OK) { 428 OH_LOG_INFO(LOG_APP, "OH_PreviewOutput_Release success "); 429 } else { 430 OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_Release failed. %d ", ret); 431 } 432 433 // 释放拍照输出流。 434 ret = OH_PhotoOutput_Release(photoOutput); 435 if (ret == CAMERA_OK) { 436 OH_LOG_INFO(LOG_APP, "OH_PhotoOutput_Release success "); 437 } else { 438 OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_Release failed. %d ", ret); 439 } 440 441 // 释放会话。 442 ret = OH_CaptureSession_Release(captureSession); 443 if (ret == CAMERA_OK) { 444 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Release success "); 445 } else { 446 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Release failed. %d ", ret); 447 } 448 449 // 资源释放。 450 ret = OH_CameraManager_DeleteSupportedCameras(cameraManager, cameras, size); 451 if (ret != CAMERA_OK) { 452 OH_LOG_ERROR(LOG_APP, "Delete Cameras failed."); 453 } else { 454 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_DeleteSupportedCameras. ok"); 455 } 456 ret = OH_CameraManager_DeleteSupportedCameraOutputCapability(cameraManager, cameraOutputCapability); 457 if (ret != CAMERA_OK) { 458 OH_LOG_ERROR(LOG_APP, "Delete Cameras failed."); 459 } else { 460 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_DeleteSupportedCameraOutputCapability. ok"); 461 } 462 ret = OH_Camera_DeleteCameraManager(cameraManager); 463 if (ret != CAMERA_OK) { 464 OH_LOG_ERROR(LOG_APP, "Delete Cameras failed."); 465 } else { 466 OH_LOG_ERROR(LOG_APP, "OH_Camera_DeleteCameraManager. ok"); 467 } 468 } 469 ```