• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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