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