1# 录像实践(C/C++) 2 3在开发相机应用时,需要先参考开发准备[申请相关权限](camera-preparation.md)。 4 5当前示例提供完整的录像流程及其接口调用顺序的介绍。对于单个流程(如设备输入、会话管理、录像)的介绍请参考[相机开发指导(Native)](camera-preparation.md)的具体章节。 6 7## 开发流程 8 9在获取到相机支持的输出流能力后,开始创建录像流,开发流程如下。 10 11 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.h。 25 ```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 ```