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