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