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 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.h。 31 ```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 ```