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