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