1# Photo Capture Sample (C/C++)
2
3Before developing a camera application, request permissions by following the instructions provided in [Camera Development Preparations](camera-preparation.md).
4
5This topic provides sample code that covers the complete photo capture process and the API calling sequence. For details about a single process (such as device input, session management, and photo capture), see the corresponding C/C++ development guide links provided in [Camera Development Preparations](camera-preparation.md).
6
7## Development Process
8
9After obtaining the output stream capabilities supported by the camera, create a photo stream. The development process is as follows:
10
11![Photographing Development Process](figures/photographing-ndk-development-process.png)
12
13## Sample Code
14
151. Link the dynamic library in the CMake script.
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. Import the NDK APIs on the C++ side, and perform photo capture based on the surface ID passed in.
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        // Read the size attribute of OH_ImageNative.
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        // Read the number of elements in the component list of 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        // Read the component list of 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        // Read the buffer object corresponding to the first component of 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        // Read the size of the buffer corresponding to the first component of 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        // Read the row stride corresponding to the first component of 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        // Read the pixel stride corresponding to the first component of 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        // Map the ION memory to the process address space.
157        void *virAddr = nullptr; // Point to the virtual address of the mapped memory. After unmapping, the pointer is invalid.
158        int32_t ret = OH_NativeBuffer_Map(nativeBuffer, &virAddr); // After mapping, the start address of the memory is returned through the parameter virAddr.
159        OH_LOG_INFO(LOG_APP, "OnPhotoAvailable OH_NativeBuffer_Map err:%{public}d", ret);
160        // Pass the processed buffer to the ArkTS side through the callback for image display or storage (using a security component). For details, see Photo Capture (C/C++).
161        auto cb = (void (*)(void *, size_t))(bufferCb);
162        cb(virAddr, nativeBufferSize);
163        // After the processing is complete, unmap and release the buffer.
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        // Create a CameraManager object.
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        // Listen for camera status changes.
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        // Obtain the camera list.
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        // Create a camera input stream.
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        // Listen for camera input errors.
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        // Open the camera.
214        ret = OH_CameraInput_Open(cameraInput);
215        if (ret != CAMERA_OK) {
216          OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Open failed.");
217        }
218
219        // Obtain the output streams supported by the camera.
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        // Create a preview output stream, with the previewSurfaceId parameter set to the ID of the surface provided by the XComponent.
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        // Listen for preview output errors.
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        // Create a photo output stream.
250        ret_ = OH_CameraManager_CreatePhotoOutputWithoutSurface(cameraManager, photoProfile, &photoOutput);
251
252        // Listen for the one-time photo capture callback.
253        ret_ = OH_PhotoOutput_RegisterPhotoAvailableCallback(photoOutput, OnPhotoAvailable);
254
255        // Create a session.
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        // Listen for session errors.
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        // Start configuration for the session.
268        ret = OH_CaptureSession_BeginConfig(captureSession);
269        if (ret != CAMERA_OK) {
270          OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed.");
271        }
272
273        // Add the camera input stream to the session.
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        // Add the preview output stream to the session.
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        // Add the photo output stream to the session.
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        // Commit the session configuration.
292        ret = OH_CaptureSession_CommitConfig(captureSession);
293        if (ret != CAMERA_OK) {
294          OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed.");
295        }
296
297        // Start the session.
298        ret = OH_CaptureSession_Start(captureSession);
299        if (ret != CAMERA_OK) {
300          OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed.");
301        }
302
303        // Check whether the camera has flash.
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        // Check whether a flash mode is supported.
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          // Set the flash mode.
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          // Obtain the flash mode in use.
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        // Check whether the continuous auto focus is supported.
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        // Obtain the zoom ratio range supported by the camera.
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        // Set a zoom ratio.
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        // Obtain the zoom ratio of the camera.
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        // Take photos without photo capture settings.
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        // Stop the session.
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        // Release the camera input stream.
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        // Release the preview output stream.
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        // Release the photo output stream.
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        // Release the session.
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        // Release the resources.
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    ```
458