• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 录像实践(C/C++)
2<!--Kit: Camera Kit-->
3<!--Subsystem: Multimedia-->
4<!--Owner: @qano-->
5<!--Designer: @leo_ysl-->
6<!--Tester: @xchaosioda-->
7<!--Adviser: @zengyawen-->
8
9在开发相机应用时,需要先[申请相关权限](camera-preparation.md)。
10
11当前示例提供完整的录像流程及其接口调用顺序的介绍。对于单个流程(如设备输入、会话管理、录像)的介绍请参考[相机开发指导(Native)](camera-preparation.md)的具体章节。
12
13## 开发流程
14
15在获取到相机支持的输出流能力后,开始创建录像流,开发流程如下。
16
17![Recording Development Process](figures/recording-ndk-development-process.png)
18
19## 完整示例
20
211. 在CMake脚本中链接相关动态库。
22    ```txt
23    target_link_libraries(entry PUBLIC
24        libace_napi.z.so
25        libohcamera.so
26        libhilog_ndk.z.so
27    )
28    ```
29
302. 创建头文件ndk_camera.h31   ```c++
32   #include "ohcamera/camera.h"
33   #include "ohcamera/camera_input.h"
34   #include "ohcamera/capture_session.h"
35   #include "ohcamera/photo_output.h"
36   #include "ohcamera/preview_output.h"
37   #include "ohcamera/video_output.h"
38   #include "ohcamera/camera_manager.h"
39
40   class NDKCamera {
41   public:
42       ~NDKCamera();
43       NDKCamera(char* previewId, char* videoId);
44   };
45   ```
46
473. cpp侧导入NDK接口,并根据传入的SurfaceId进行录像。
48    ```c++
49    #include "hilog/log.h"
50    #include "ndk_camera.h"
51    #include <cmath>
52
53    bool IsAspectRatioEqual(float videoAspectRatio, float previewAspectRatio)
54    {
55        float epsilon = 1e-6f;
56        return fabsf(videoAspectRatio - previewAspectRatio) <= epsilon;
57    }
58
59    void OnCameraInputError(const Camera_Input* cameraInput, Camera_ErrorCode errorCode)
60    {
61        OH_LOG_INFO(LOG_APP, "OnCameraInput errorCode = %{public}d", errorCode);
62    }
63
64    CameraInput_Callbacks* GetCameraInputListener(void)
65    {
66        static CameraInput_Callbacks cameraInputCallbacks = {
67            .onError = OnCameraInputError
68        };
69        return &cameraInputCallbacks;
70    }
71
72    void CaptureSessionOnFocusStateChange(Camera_CaptureSession* session, Camera_FocusState focusState)
73    {
74        OH_LOG_INFO(LOG_APP, "CaptureSessionOnFocusStateChange");
75    }
76
77    void CaptureSessionOnError(Camera_CaptureSession* session, Camera_ErrorCode errorCode)
78    {
79        OH_LOG_INFO(LOG_APP, "CaptureSessionOnError = %{public}d", errorCode);
80    }
81
82    CaptureSession_Callbacks* GetCaptureSessionRegister(void)
83    {
84        static CaptureSession_Callbacks captureSessionCallbacks = {
85            .onFocusStateChange = CaptureSessionOnFocusStateChange,
86            .onError = CaptureSessionOnError
87        };
88        return &captureSessionCallbacks;
89    }
90
91    void VideoOutputOnFrameStart(Camera_VideoOutput* videoOutput)
92    {
93        OH_LOG_INFO(LOG_APP, "VideoOutputOnFrameStart");
94    }
95
96    void VideoOutputOnFrameEnd(Camera_VideoOutput* videoOutput, int32_t frameCount)
97    {
98        OH_LOG_INFO(LOG_APP, "VideoOutput frameCount = %{public}d", frameCount);
99    }
100
101    void VideoOutputOnError(Camera_VideoOutput* videoOutput, Camera_ErrorCode errorCode)
102    {
103        OH_LOG_INFO(LOG_APP, "VideoOutput errorCode = %{public}d", errorCode);
104    }
105
106    VideoOutput_Callbacks* GetVideoOutputListener(void)
107    {
108        static VideoOutput_Callbacks videoOutputListener = {
109            .onFrameStart = VideoOutputOnFrameStart,
110            .onFrameEnd = VideoOutputOnFrameEnd,
111            .onError = VideoOutputOnError
112        };
113        return &videoOutputListener;
114    }
115
116    void CameraManagerStatusCallback(Camera_Manager* cameraManager, Camera_StatusInfo* status)
117    {
118        OH_LOG_INFO(LOG_APP, "CameraManagerStatusCallback is called");
119    }
120
121    CameraManager_Callbacks* GetCameraManagerListener()
122    {
123        static CameraManager_Callbacks cameraManagerListener = {
124            .onCameraStatus = CameraManagerStatusCallback
125        };
126        return &cameraManagerListener;
127    }
128
129    NDKCamera::NDKCamera(char* previewId, char* videoId)
130    {
131        Camera_Manager* cameraManager = nullptr;
132        Camera_Device* cameras = nullptr;
133        Camera_CaptureSession* captureSession = nullptr;
134        Camera_OutputCapability* cameraOutputCapability = nullptr;
135        Camera_VideoOutput* videoOutput = nullptr;
136        const Camera_Profile* previewProfile = nullptr;
137        const Camera_Profile* photoProfile = nullptr;
138        const Camera_VideoProfile* videoProfile = nullptr;
139        Camera_PreviewOutput* previewOutput = nullptr;
140        Camera_PhotoOutput* photoOutput = nullptr;
141        Camera_Input* cameraInput = nullptr;
142        uint32_t size = 0;
143        uint32_t cameraDeviceIndex = 0;
144        char* videoSurfaceId = videoId;
145        char* previewSurfaceId = previewId;
146        // 创建CameraManager对象。
147        Camera_ErrorCode ret = OH_Camera_GetCameraManager(&cameraManager);
148        if (cameraManager == nullptr || ret != CAMERA_OK) {
149            OH_LOG_ERROR(LOG_APP, "OH_Camera_GetCameraManager failed.");
150            return;
151        }
152        // 监听相机状态变化。
153        ret = OH_CameraManager_RegisterCallback(cameraManager, GetCameraManagerListener());
154        if (ret != CAMERA_OK) {
155            OH_LOG_ERROR(LOG_APP, "OH_CameraManager_RegisterCallback failed.");
156            return;
157        }
158
159        // 获取相机列表。
160        ret = OH_CameraManager_GetSupportedCameras(cameraManager, &cameras, &size);
161        if (cameras == nullptr || size <= 0 || ret != CAMERA_OK) {
162            OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameras failed.");
163            return;
164        }
165
166        for (int index = 0; index < size; index++) {
167            OH_LOG_ERROR(LOG_APP, "cameraId  =  %{public}s ", cameras[index].cameraId);              // 获取相机ID。
168            OH_LOG_ERROR(LOG_APP, "cameraPosition  =  %{public}d ", cameras[index].cameraPosition);  // 获取相机位置。
169            OH_LOG_ERROR(LOG_APP, "cameraType  =  %{public}d ", cameras[index].cameraType);          // 获取相机类型。
170            OH_LOG_ERROR(LOG_APP, "connectionType  =  %{public}d ", cameras[index].connectionType);  // 获取相机连接类型。
171        }
172
173        if (size < cameraDeviceIndex + 1) {
174            OH_LOG_ERROR(LOG_APP, "cameraDeviceIndex is invalid.");
175            return;
176        }
177
178        // 获取相机设备支持的输出流能力。
179        ret = OH_CameraManager_GetSupportedCameraOutputCapability(cameraManager, &cameras[cameraDeviceIndex],
180                                                                &cameraOutputCapability);
181        if (cameraOutputCapability == nullptr || ret != CAMERA_OK) {
182            OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameraOutputCapability failed.");
183            return;
184        }
185
186        if (cameraOutputCapability->previewProfiles == nullptr) {
187            OH_LOG_ERROR(LOG_APP, "previewProfiles == null");
188            return;
189        }
190        previewProfile = cameraOutputCapability->previewProfiles[0];
191        OH_LOG_INFO(LOG_APP, "previewProfile width: %{public}, height: %{public}.", previewProfile->size.width,
192            previewProfile->size.height);
193        if (cameraOutputCapability->photoProfiles == nullptr) {
194            OH_LOG_ERROR(LOG_APP, "photoProfiles == null");
195            return;
196        }
197        photoProfile = cameraOutputCapability->photoProfiles[0];
198
199        if (cameraOutputCapability->videoProfiles == nullptr) {
200            OH_LOG_ERROR(LOG_APP, "videoProfiles == null");
201            return;
202        }
203        // 预览流宽高比要与录像流的宽高比一致,如果录制的是hdr视频,请筛选支持hdr的Camera_VideoProfile。
204        Camera_VideoProfile** videoProfiles = cameraOutputCapability->videoProfiles;
205        for (int index = 0; index < cameraOutputCapability->videoProfilesSize; index++) {
206            bool isEqual = IsAspectRatioEqual((float)videoProfiles[index]->size.width / videoProfiles[index]->size.height,
207                (float)previewProfile->size.width / previewProfile->size.height);
208            // 默认筛选CAMERA_FORMAT_YUV_420_SP的profile。
209            if (isEqual && videoProfiles[index]->format == Camera_Format::CAMERA_FORMAT_YUV_420_SP) {
210                videoProfile = videoProfiles[index];
211                OH_LOG_INFO(LOG_APP, "videoProfile width: %{public}, height: %{public}.", videoProfile->size.width,
212                    videoProfile->size.height);
213                break;
214            }
215        }
216        if (videoProfile == nullptr) {
217            OH_LOG_ERROR(LOG_APP, "Get videoProfile failed.");
218            return;
219        }
220        // 创建VideoOutput对象。
221        ret = OH_CameraManager_CreateVideoOutput(cameraManager, videoProfile, videoSurfaceId, &videoOutput);
222        if (videoOutput == nullptr || ret != CAMERA_OK) {
223            OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateVideoOutput failed.");
224            return;
225        }
226
227        // 监听视频输出错误信息。
228        ret = OH_VideoOutput_RegisterCallback(videoOutput, GetVideoOutputListener());
229        if (ret != CAMERA_OK) {
230            OH_LOG_ERROR(LOG_APP, "OH_VideoOutput_RegisterCallback failed.");
231        }
232
233        //创建会话。
234        ret = OH_CameraManager_CreateCaptureSession(cameraManager, &captureSession);
235        if (captureSession == nullptr || ret != CAMERA_OK) {
236            OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCaptureSession failed.");
237            return;
238        }
239        // 监听session错误信息。
240        ret = OH_CaptureSession_RegisterCallback(captureSession, GetCaptureSessionRegister());
241        if (ret != CAMERA_OK) {
242            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_RegisterCallback failed.");
243        }
244
245        // 开始配置会话。
246        ret = OH_CaptureSession_BeginConfig(captureSession);
247        if (ret != CAMERA_OK) {
248            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed.");
249            return;
250        }
251
252        // 创建相机输入流。
253        ret = OH_CameraManager_CreateCameraInput(cameraManager, &cameras[cameraDeviceIndex], &cameraInput);
254        if (cameraInput == nullptr || ret != CAMERA_OK) {
255            OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCameraInput failed.");
256            return;
257        }
258
259        // 监听cameraInput错误信息。
260        ret = OH_CameraInput_RegisterCallback(cameraInput, GetCameraInputListener());
261        if (ret != CAMERA_OK) {
262            OH_LOG_ERROR(LOG_APP, "OH_CameraInput_RegisterCallback failed.");
263        }
264
265        // 打开相机。
266        ret = OH_CameraInput_Open(cameraInput);
267        if (ret != CAMERA_OK) {
268            OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Open failed.");
269            return;
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            return;
277        }
278
279        // 创建预览输出流,其中参数 surfaceId 参考下面 XComponent 组件,预览流为XComponent组件提供的surface。
280        ret = OH_CameraManager_CreatePreviewOutput(cameraManager, previewProfile, previewSurfaceId, &previewOutput);
281        if (previewProfile == nullptr || previewOutput == nullptr || ret != CAMERA_OK) {
282            OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput failed.");
283            return;
284        }
285
286        // 向会话中添加预览输出流。
287        ret = OH_CaptureSession_AddPreviewOutput(captureSession, previewOutput);
288        if (ret != CAMERA_OK) {
289            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPreviewOutput failed.");
290            return;
291        }
292
293        // 向会话中添加录像输出流。
294        ret = OH_CaptureSession_AddVideoOutput(captureSession, videoOutput);
295        if (ret != CAMERA_OK) {
296            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddVideoOutput failed.");
297            return;
298        }
299
300        // 提交会话配置。
301        ret = OH_CaptureSession_CommitConfig(captureSession);
302        if (ret != CAMERA_OK) {
303            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed.");
304            return;
305        }
306
307        // 启动会话。
308        ret = OH_CaptureSession_Start(captureSession);
309        if (ret != CAMERA_OK) {
310            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed.");
311            return;
312        }
313
314        // 启动录像输出流。
315        ret = OH_VideoOutput_Start(videoOutput);
316        if (ret != CAMERA_OK) {
317            OH_LOG_ERROR(LOG_APP, "OH_VideoOutput_Start failed.");
318            return;
319        }
320
321        // 开始录像 ts侧调用avRecorder.start()。
322
323        // 停止录像输出流。
324        ret = OH_VideoOutput_Stop(videoOutput);
325        if (ret != CAMERA_OK) {
326            OH_LOG_ERROR(LOG_APP, "OH_VideoOutput_Stop failed.");
327        }
328
329        // 停止录像 ts侧调用avRecorder.stop()。
330
331        // 停止当前会话。
332        ret = OH_CaptureSession_Stop(captureSession);
333        if (ret == CAMERA_OK) {
334            OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Stop success ");
335        } else {
336            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Stop failed. %d ", ret);
337        }
338
339        // 释放相机输入流。
340        ret = OH_CameraInput_Close(cameraInput);
341        if (ret == CAMERA_OK) {
342            OH_LOG_INFO(LOG_APP, "OH_CameraInput_Close success ");
343        } else {
344            OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Close failed. %d ", ret);
345        }
346
347        // 释放预览输出流。
348        ret = OH_PreviewOutput_Release(previewOutput);
349        if (ret == CAMERA_OK) {
350            OH_LOG_INFO(LOG_APP, "OH_PreviewOutput_Release success ");
351        } else {
352            OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_Release failed. %d ", ret);
353        }
354
355        // 释放录像输出流。
356        ret = OH_VideoOutput_Release(videoOutput);
357        if (ret == CAMERA_OK) {
358            OH_LOG_INFO(LOG_APP, "OH_VideoOutput_Release success ");
359        } else {
360            OH_LOG_ERROR(LOG_APP, "OH_VideoOutput_Release failed. %d ", ret);
361        }
362
363        // 释放会话。
364        ret = OH_CaptureSession_Release(captureSession);
365        if (ret == CAMERA_OK) {
366            OH_LOG_INFO(LOG_APP, "OH_CaptureSession_Release success ");
367        } else {
368            OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Release failed. %d ", ret);
369        }
370
371        // 资源释放。
372        ret = OH_CameraManager_DeleteSupportedCameras(cameraManager, cameras, size);
373        if (ret != CAMERA_OK) {
374            OH_LOG_ERROR(LOG_APP, "Delete Cameras failed.");
375        } else {
376            OH_LOG_ERROR(LOG_APP, "OH_CameraManager_DeleteSupportedCameras. ok");
377        }
378        ret = OH_CameraManager_DeleteSupportedCameraOutputCapability(cameraManager, cameraOutputCapability);
379        if (ret != CAMERA_OK) {
380            OH_LOG_ERROR(LOG_APP, "Delete Cameras failed.");
381        } else {
382            OH_LOG_ERROR(LOG_APP, "OH_CameraManager_DeleteSupportedCameraOutputCapability success");
383        }
384        ret = OH_Camera_DeleteCameraManager(cameraManager);
385        if (ret != CAMERA_OK) {
386            OH_LOG_ERROR(LOG_APP, "Delete Cameras failed.");
387        } else {
388            OH_LOG_ERROR(LOG_APP, "OH_Camera_DeleteCameraManager success");
389        }
390    }
391    ```