1# Photo Capture (C/C++) 2<!--Kit: Camera Kit--> 3<!--Subsystem: Multimedia--> 4<!--Owner: @qano--> 5<!--SE: @leo_ysl--> 6<!--TSE: @xchaosioda--> 7 8Photo capture is an important function of the camera application. Based on the complex logic of the camera hardware, the camera module provides APIs for you to set information such as resolution, flash, focal length, photo quality, and rotation angle. 9 10## How to Develop 11 12Read [Camera](../../reference/apis-camera-kit/capi-oh-camera.md) for the API reference. 13 141. Import the NDK, which provides camera-related attributes and methods. 15 16 ```c++ 17 // Include the NDK header files. 18 #include <cstdint> 19 #include <cstdlib> 20 #include <cstring> 21 #include <string.h> 22 #include "hilog/log.h" 23 #include "ohcamera/camera.h" 24 #include "ohcamera/camera_input.h" 25 #include "ohcamera/capture_session.h" 26 #include "ohcamera/photo_output.h" 27 #include "ohcamera/preview_output.h" 28 #include "ohcamera/video_output.h" 29 #include "ohcamera/camera_manager.h" 30 #include <multimedia/image_framework/image/image_native.h> 31 ``` 32 332. Link the dynamic library in the CMake script. 34 35 ```txt 36 target_link_libraries(entry PUBLIC 37 libace_napi.z.so 38 libhilog_ndk.z.so 39 libnative_buffer.so 40 libohcamera.so 41 libohimage.so 42 libohfileuri.so 43 ) 44 ``` 45 463. Create and open a camera device. For details, see steps 3 to 5 in [Device Input Management (C/C++)](./native-camera-device-input.md). 47 484. Select the output stream capability supported by the camera device and create a photo output stream. 49 50 Call [OH_CameraManager_CreatePhotoOutputWithoutSurface()](../../reference/apis-camera-kit/capi-camera-manager-h.md#oh_cameramanager_createphotooutputwithoutsurface) to create a photo output stream. 51 52 ```c++ 53 Camera_PhotoOutput* CreatePhotoOutput(Camera_Manager* cameraManager, const Camera_Profile* photoProfile) { 54 Camera_PhotoOutput* photoOutput = nullptr; 55 // Create a photo output stream without passing a surface ID. 56 Camera_ErrorCode ret = OH_CameraManager_CreatePhotoOutputWithoutSurface(cameraManager, photoProfile, &photoOutput); 57 if (photoOutput == nullptr || ret != CAMERA_OK) { 58 OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePhotoOutputWithoutSurface failed."); 59 } 60 return photoOutput; 61 } 62 ``` 63 645. Register a one-time photo capture callback, which is defined as **PhotoAvailable**. If your application requires rapid image display, use the deferred photo delivery callback, which is defined as [PhotoAssetAvailable](./native-camera-deferred-capture.md). 65 66 > **NOTE** 67 > 68 > If the **PhotoAssetAvailable** callback has been registered and the **PhotoAvailable** callback is registered after the session starts, the stream will be restarted. In this case, only the **PhotoAssetAvailable** callback takes effect. 69 > 70 > Therefore, you are not advised to register both **PhotoAssetAvailable** and **PhotoAvailable**. 71 72 The development process is as follows: 73 74 - Register the callback before the session commits the configuration. 75 - Obtain the image information from the callback, parse the buffer data, and perform custom service processing. 76 - Pass the processed buffer to the ArkTS side through the callback for image display or storage (using a security component). 77 - Unregister the callback when it is no longer required. 78 79 ```c++ 80 // Save the buffer processing callback registered on the NAPI side. 81 static void* bufferCb = nullptr; 82 Camera_ErrorCode RegisterBufferCb(void* cb) { 83 OH_LOG_INFO(LOG_APP, " RegisterBufferCb start"); 84 if (cb == nullptr) { 85 OH_LOG_INFO(LOG_APP, " RegisterBufferCb invalid error"); 86 return CAMERA_INVALID_ARGUMENT; 87 } 88 bufferCb = cb; 89 return CAMERA_OK; 90 } 91 92 // One-time photo capture callback. 93 void OnPhotoAvailable(Camera_PhotoOutput* photoOutput, OH_PhotoNative* photo) { 94 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable start!"); 95 OH_ImageNative* imageNative; 96 Camera_ErrorCode errCode = OH_PhotoNative_GetMainImage(photo, &imageNative); 97 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable errCode:%{public}d imageNative:%{public}p", errCode, imageNative); 98 // Read the size attribute of OH_ImageNative. 99 Image_Size size; 100 Image_ErrorCode imageErr = OH_ImageNative_GetImageSize(imageNative, &size); 101 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d width:%{public}d height:%{public}d", imageErr, 102 size.width, size.height); 103 // Read the number of elements in the component list of OH_ImageNative. 104 size_t componentTypeSize = 0; 105 imageErr = OH_ImageNative_GetComponentTypes(imageNative, nullptr, &componentTypeSize); 106 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d componentTypeSize:%{public}zu", imageErr, 107 componentTypeSize); 108 // Read the component list of OH_ImageNative. 109 uint32_t* components = new uint32_t[componentTypeSize]; 110 imageErr = OH_ImageNative_GetComponentTypes(imageNative, &components, &componentTypeSize); 111 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_ImageNative_GetComponentTypes imageErr:%{public}d", imageErr); 112 // Read the buffer object corresponding to the first component of OH_ImageNative. 113 OH_NativeBuffer* nativeBuffer = nullptr; 114 imageErr = OH_ImageNative_GetByteBuffer(imageNative, components[0], &nativeBuffer); 115 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_ImageNative_GetByteBuffer imageErr:%{public}d", imageErr); 116 // Read the size of the buffer corresponding to the first component of OH_ImageNative. 117 size_t nativeBufferSize = 0; 118 imageErr = OH_ImageNative_GetBufferSize(imageNative, components[0], &nativeBufferSize); 119 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d nativeBufferSize:%{public}zu", imageErr, 120 nativeBufferSize); 121 // Read the row stride corresponding to the first component of OH_ImageNative. 122 int32_t rowStride = 0; 123 imageErr = OH_ImageNative_GetRowStride(imageNative, components[0], &rowStride); 124 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d rowStride:%{public}d", imageErr, rowStride); 125 // Read the pixel stride corresponding to the first component of OH_ImageNative. 126 int32_t pixelStride = 0; 127 imageErr = OH_ImageNative_GetPixelStride(imageNative, components[0], &pixelStride); 128 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable imageErr:%{public}d pixelStride:%{public}d", imageErr, pixelStride); 129 // Map the ION memory to the process address space. 130 void* virAddr = nullptr; // Point to the virtual address of the mapped memory. After unmapping, the pointer is invalid. 131 int32_t ret = OH_NativeBuffer_Map(nativeBuffer, &virAddr); // After mapping, the start address of the memory is returned through the parameter virAddr. 132 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_NativeBuffer_Map err:%{public}d", ret); 133 // Call the buffer callback at the NAPI layer. 134 auto cb = (void (*)(void *, size_t))(bufferCb); 135 cb(virAddr, nativeBufferSize); 136 // Release resources. 137 delete[] components; 138 OH_ImageNative_Release(imageNative); 139 ret = OH_NativeBuffer_Unmap(nativeBuffer); // After the processing is complete, unmap and release the buffer. 140 if (ret != 0) { 141 OH_LOG_ERROR(LOG_APP, "OnPhotoAvailable OH_NativeBuffer_Unmap error:%{public}d", ret); 142 } 143 OH_LOG_INFO(LOG_APP, "OnPhotoAvailable end"); 144 } 145 146 // Register the PhotoAvailableCallback callback. 147 Camera_ErrorCode PhotoOutputRegisterPhotoAvailableCallback(Camera_PhotoOutput* photoOutput) { 148 OH_LOG_INFO(LOG_APP, "PhotoOutputRegisterPhotoAvailableCallback start!"); 149 Camera_ErrorCode ret = OH_PhotoOutput_RegisterPhotoAvailableCallback(photoOutput, OnPhotoAvailable); 150 if (ret != CAMERA_OK) { 151 OH_LOG_ERROR(LOG_APP, "PhotoOutputRegisterPhotoAvailableCallback failed."); 152 } 153 OH_LOG_INFO(LOG_APP, "PhotoOutputRegisterPhotoAvailableCallback return with ret code: %{public}d!", ret); 154 return ret; 155 } 156 157 // Unregister the PhotoAvailableCallback callback. 158 Camera_ErrorCode PhotoOutputUnRegisterPhotoAvailableCallback(Camera_PhotoOutput* photoOutput) { 159 OH_LOG_INFO(LOG_APP, "PhotoOutputUnRegisterPhotoAvailableCallback start!"); 160 Camera_ErrorCode ret = OH_PhotoOutput_UnregisterPhotoAvailableCallback(photoOutput, OnPhotoAvailable); 161 if (ret != CAMERA_OK) { 162 OH_LOG_ERROR(LOG_APP, "PhotoOutputUnRegisterPhotoAvailableCallback failed."); 163 } 164 OH_LOG_INFO(LOG_APP, "PhotoOutputUnRegisterPhotoAvailableCallback return with ret code: %{public}d!", ret); 165 return ret; 166 } 167 ``` 168 169 Sample code for buffer processing at the NAPI layer: 170 171 ```c++ 172 static napi_ref bufferCbRef_ = nullptr; 173 static napi_env env_; 174 size_t g_size = 0; 175 176 // Buffer callback at the NAPI layer. 177 static void BufferCb(void* buffer, size_t size) { 178 OH_LOG_INFO(LOG_APP, "BufferCb size:%{public}zu", size); 179 g_size = size; 180 napi_value asyncResource = nullptr; 181 napi_value asyncResourceName = nullptr; 182 napi_async_work work; 183 184 void* copyBuffer = malloc(size); 185 if (copyBuffer == nullptr) { 186 return; 187 } 188 OH_LOG_INFO(LOG_APP, "BufferCb copyBuffer:%{public}p", copyBuffer); 189 // Use std::memcpy to copy the content in the buffer to the copyBuffer. 190 std::memcpy(copyBuffer, buffer, size); 191 napi_create_string_utf8(env_, "BufferCb", NAPI_AUTO_LENGTH, &asyncResourceName); 192 napi_status status = napi_create_async_work( 193 env_, asyncResource, asyncResourceName, [](napi_env env, void* copyBuffer) {}, 194 [](napi_env env, napi_status status, void* copyBuffer) { 195 napi_value retVal; 196 napi_value callback = nullptr; 197 void* data = nullptr; 198 napi_value arrayBuffer = nullptr; 199 size_t bufferSize = g_size; 200 napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer); 201 std::memcpy(data, copyBuffer, bufferSize); 202 OH_LOG_INFO(LOG_APP, "BufferCb g_size: %{public}zu", g_size); 203 napi_get_reference_value(env, bufferCbRef_, &callback); 204 if (callback) { 205 OH_LOG_INFO(LOG_APP, "BufferCb callback is full"); 206 } else { 207 OH_LOG_ERROR(LOG_APP, "BufferCb callback is null"); 208 } 209 // Call the buffer processing callback function at the ArkTS side to pass the image arrayBuffer for display or storage. 210 napi_call_function(env, nullptr, callback, 1, &arrayBuffer, &retVal); 211 // Clear the memory. 212 free(data); // Release the memory allocated during asynchronous work. 213 }, 214 copyBuffer, &work); 215 216 // Error check: The memory is released when the asynchronous work fails to be created. 217 if (status != napi_ok) { 218 OH_LOG_ERROR(LOG_APP, "Failed to create async work"); 219 free(copyBuffer); // Release the allocated memory. 220 return; 221 } 222 napi_queue_async_work_with_qos(env_, work, napi_qos_user_initiated); 223 } 224 225 // Save the buffer processing callback function passed from ArkTS. 226 static napi_value SetBufferCb(napi_env env, napi_callback_info info) { 227 OH_LOG_INFO(LOG_APP, "SetBufferCb start"); 228 napi_value result; 229 napi_get_undefined(env, &result); 230 231 napi_value argValue[1] = {nullptr}; 232 size_t argCount = 1; 233 napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr); 234 235 env_ = env; 236 napi_create_reference(env, argValue[0], 1, &bufferCbRef_); 237 if (bufferCbRef_) { 238 OH_LOG_INFO(LOG_APP, "SetBufferCb callbackRef is full"); 239 } else { 240 OH_LOG_ERROR(LOG_APP, "SetBufferCb callbackRef is null"); 241 } 242 // Register the buffer callback to be passed to the NAPI layer on the ArkTS side. 243 RegisterBufferCb((void *)BufferCb); 244 return result; 245 } 246 ``` 247 2486. Create a photo session. For details, see [Camera Session Management (C/C++)](./native-camera-session-management.md). 249 2507. (Optional) Set photo capture parameters. 251 You can set camera parameters to adjust photo capture functions, including the flash, zoom ratio, and focal length. 252 253 ```c++ 254 // Check whether the camera has flash. 255 bool HasFlash(Camera_CaptureSession* captureSession) 256 { 257 bool hasFlash = false; 258 Camera_ErrorCode ret = OH_CaptureSession_HasFlash(captureSession, &hasFlash); 259 if (ret != CAMERA_OK) { 260 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_HasFlash failed."); 261 } 262 if (hasFlash) { 263 OH_LOG_INFO(LOG_APP, "hasFlash success"); 264 } else { 265 OH_LOG_ERROR(LOG_APP, "hasFlash fail"); 266 } 267 return hasFlash; 268 } 269 270 // Check whether a flash mode is supported. 271 bool IsFlashModeSupported(Camera_CaptureSession* captureSession, Camera_FlashMode flashMode) 272 { 273 bool isSupported = false; 274 Camera_ErrorCode ret = OH_CaptureSession_IsFlashModeSupported(captureSession, flashMode, &isSupported); 275 if (ret != CAMERA_OK) { 276 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFlashModeSupported failed."); 277 } 278 return isSupported; 279 } 280 // Call OH_CaptureSession_SetFlashMode when the specified mode is supported. 281 Camera_ErrorCode SetFocusMode(Camera_CaptureSession* captureSession, Camera_FlashMode flashMode) 282 { 283 Camera_ErrorCode ret = OH_CaptureSession_SetFlashMode(captureSession, flashMode); 284 if (ret == CAMERA_OK) { 285 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetFlashMode success."); 286 } else { 287 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFlashMode failed. %{public}d ", ret); 288 } 289 return ret; 290 } 291 292 // Check whether the continuous auto focus is supported. 293 bool IsFocusModeSupported(Camera_CaptureSession* captureSession, Camera_FocusMode focusMode) 294 { 295 bool isFocusModeSupported = false; 296 Camera_ErrorCode ret = OH_CaptureSession_IsFocusModeSupported(captureSession, focusMode, &isFocusModeSupported); 297 if (ret != CAMERA_OK) { 298 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_IsFocusModeSupported failed."); 299 } 300 return isFocusModeSupported; 301 } 302 // Call OH_CaptureSession_SetFocusMode when the specified mode is supported. 303 Camera_ErrorCode SetFocusMode(Camera_CaptureSession* captureSession, Camera_FocusMode focusMode) 304 { 305 Camera_ErrorCode ret = OH_CaptureSession_SetFocusMode(captureSession, focusMode); 306 if (ret != CAMERA_OK) { 307 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetFocusMode failed. %{public}d ", ret); 308 } 309 return ret; 310 } 311 312 // Obtain the zoom ratio range supported by the camera. 313 Camera_ErrorCode GetZoomRatioRange(Camera_CaptureSession* captureSession, float* minZoom, float* maxZoom) 314 { 315 Camera_ErrorCode ret = OH_CaptureSession_GetZoomRatioRange(captureSession, minZoom, maxZoom); 316 if (ret != CAMERA_OK) { 317 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_GetZoomRatioRange failed."); 318 } else { 319 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_GetZoomRatioRange success. minZoom: %{public}f, maxZoom:%{public}f", 320 *minZoom, *maxZoom); 321 } 322 return ret; 323 } 324 325 // Set the zoom ratio, which must be within the allowed range. 326 Camera_ErrorCode SetZoomRatio(Camera_CaptureSession* captureSession, float zoom) 327 { 328 Camera_ErrorCode ret = OH_CaptureSession_SetZoomRatio(captureSession, zoom); 329 if (ret == CAMERA_OK) { 330 OH_LOG_INFO(LOG_APP, "OH_CaptureSession_SetZoomRatio success."); 331 } else { 332 OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetZoomRatio failed. %{public}d ", ret); 333 } 334 return ret; 335 } 336 ``` 337 3388. Trigger photo capture. 339 340 Call [OH_PhotoOutput_Capture()](../../reference/apis-camera-kit/capi-photo-output-h.md#oh_photooutput_capture) to trigger photo capture. 341 342 ```c++ 343 Camera_ErrorCode Capture(Camera_PhotoOutput* photoOutput) 344 { 345 Camera_ErrorCode ret = OH_PhotoOutput_Capture(photoOutput); 346 if (ret == CAMERA_OK) { 347 OH_LOG_INFO(LOG_APP, "OH_PhotoOutput_Capture success "); 348 } else { 349 OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_Capture failed. %d ", ret); 350 } 351 return ret; 352 } 353 ``` 354 355## Status Listening 356 357During camera application development, you can listen for the status of the photo output stream, including the start of the photo stream, the start and end of the photo frame, and the errors of the photo output stream. 358 359- Register the **'onFrameStart'** event to listen for photo capture start events. This event can be registered when a PhotoOutput instance is created and is triggered when the bottom layer starts exposure for photo capture for the first time. The capture ID is returned. 360 ```c++ 361 void PhotoOutputOnFrameStart(Camera_PhotoOutput* photoOutput) 362 { 363 OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameStart"); 364 } 365 void PhotoOutputOnFrameShutter(Camera_PhotoOutput* photoOutput, Camera_FrameShutterInfo* info) 366 { 367 OH_LOG_INFO(LOG_APP, "PhotoOutputOnFrameShutter"); 368 } 369 ``` 370 371- Register the **'onFrameEnd'** event to listen for photo capture end events. This event can be registered when a PhotoOutput instance is created. 372 373 ```c++ 374 void PhotoOutputOnFrameEnd(Camera_PhotoOutput* photoOutput, int32_t frameCount) 375 { 376 OH_LOG_INFO(LOG_APP, "PhotoOutput frameCount = %{public}d", frameCount); 377 } 378 ``` 379 380- Register the **'onError'** event to listen for photo output errors. The callback function returns an error code when an API is incorrectly used. For details about the error code types, see [Camera_ErrorCode](../../reference/apis-camera-kit/capi-camera-h.md#camera_errorcode). 381 382 ```c++ 383 void PhotoOutputOnError(Camera_PhotoOutput* photoOutput, Camera_ErrorCode errorCode) 384 { 385 OH_LOG_INFO(LOG_APP, "PhotoOutput errorCode = %{public}d", errorCode); 386 } 387 ``` 388 ```c++ 389 PhotoOutput_Callbacks* GetPhotoOutputListener() 390 { 391 static PhotoOutput_Callbacks photoOutputListener = { 392 .onFrameStart = PhotoOutputOnFrameStart, 393 .onFrameShutter = PhotoOutputOnFrameShutter, 394 .onFrameEnd = PhotoOutputOnFrameEnd, 395 .onError = PhotoOutputOnError 396 }; 397 return &photoOutputListener; 398 } 399 Camera_ErrorCode RegisterPhotoOutputCallback(Camera_PhotoOutput* photoOutput) 400 { 401 Camera_ErrorCode ret = OH_PhotoOutput_RegisterCallback(photoOutput, GetPhotoOutputListener()); 402 if (ret != CAMERA_OK) { 403 OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_RegisterCallback failed."); 404 } 405 return ret; 406 } 407 ``` 408