1# Video Recording Practices (ArkTS) 2<!--Kit: Camera Kit--> 3<!--Subsystem: Multimedia--> 4<!--Owner: @qano--> 5<!--SE: @leo_ysl--> 6<!--TSE: @xchaosioda--> 7 8Before developing a camera application, request permissions by following the instructions provided in [Requesting Camera Development Permissions](camera-preparation.md). 9 10This topic provides sample code that covers the complete recording process to help you understand the complete API calling sequence. 11 12Before referring to the sample code, you are advised to read [Device Input Management](camera-device-input.md), [Camera Session Management](camera-session-management.md), [Video Recording](camera-recording.md), and other related topics in [Camera Development (ArkTS)](camera-preparation.md). 13 14To save videos to the media library, follow the instructions provided in [Saving Media Assets](../medialibrary/photoAccessHelper-savebutton.md). 15## Development Process 16 17After obtaining the output stream capabilities supported by the camera, create a video stream. The development process is as follows: 18 19 20 21 22## Sample Code 23For details about how to obtain the context, see [Obtaining the Context of UIAbility](../../application-models/uiability-usage.md#obtaining-the-context-of-uiability). 24 25```ts 26import { camera } from '@kit.CameraKit'; 27import { BusinessError } from '@kit.BasicServicesKit'; 28import { media } from '@kit.MediaKit'; 29import { common } from '@kit.AbilityKit'; 30import { fileIo as fs } from '@kit.CoreFileKit'; 31 32async function videoRecording(context: common.Context, surfaceId: string): Promise<void> { 33 // Create a CameraManager object. 34 let cameraManager: camera.CameraManager = camera.getCameraManager(context); 35 if (!cameraManager) { 36 console.error("camera.getCameraManager error"); 37 return; 38 } 39 40 // Listen for camera status changes. 41 cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => { 42 if (err !== undefined && err.code !== 0) { 43 console.error('cameraStatus with errorCode = ' + err.code); 44 return; 45 } 46 console.info(`camera : ${cameraStatusInfo.camera.cameraId}`); 47 console.info(`status: ${cameraStatusInfo.status}`); 48 }); 49 50 // Obtain the camera list. 51 let cameraArray: Array<camera.CameraDevice> = []; 52 try { 53 cameraArray = cameraManager.getSupportedCameras(); 54 } catch (error) { 55 let err = error as BusinessError; 56 console.error(`getSupportedCameras call failed. error code: ${err.code}`); 57 } 58 59 if (cameraArray.length <= 0) { 60 console.error("cameraManager.getSupportedCameras error"); 61 return; 62 } 63 64 // Obtain the supported modes. 65 let sceneModes: Array<camera.SceneMode> = cameraManager.getSupportedSceneModes(cameraArray[0]); 66 let isSupportVideoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_VIDEO) >= 0; 67 if (!isSupportVideoMode) { 68 console.error('video mode not support'); 69 return; 70 } 71 72 // Obtain the output stream capability supported by the camera. 73 let cameraOutputCap: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(cameraArray[0], camera.SceneMode.NORMAL_VIDEO); 74 if (!cameraOutputCap) { 75 console.error("cameraManager.getSupportedOutputCapability error") 76 return; 77 } 78 console.info("outputCapability: " + JSON.stringify(cameraOutputCap)); 79 80 let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles; 81 if (!previewProfilesArray) { 82 console.error("createOutput previewProfilesArray == null || undefined"); 83 } 84 85 let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles; 86 if (!photoProfilesArray) { 87 console.error("createOutput photoProfilesArray == null || undefined"); 88 } 89 90 let videoProfilesArray: Array<camera.VideoProfile> = cameraOutputCap.videoProfiles; 91 if (!videoProfilesArray || videoProfilesArray.length === 0) { 92 console.error("createOutput videoProfilesArray == null || undefined"); 93 } 94 95 // The width and height of videoProfile must be the same as those of AVRecorderProfile. 96 // In this sample code, the first video profile is selected. You need to select a video profile as required. 97 let videoProfile: camera.VideoProfile = videoProfilesArray[0]; 98 let isHdr = videoProfile.format === camera.CameraFormat.CAMERA_FORMAT_YCBCR_P010 || videoProfile.format === camera.CameraFormat.CAMERA_FORMAT_YCRCB_P010; 99 // Configure the parameters based on those supported by the hardware device. 100 let aVRecorderProfile: media.AVRecorderProfile = { 101 audioBitrate: 48000, 102 audioChannels: 2, 103 audioCodec: media.CodecMimeType.AUDIO_AAC, 104 audioSampleRate: 48000, 105 fileFormat: media.ContainerFormatType.CFT_MPEG_4, 106 videoBitrate: 2000000, 107 videoCodec: isHdr ? media.CodecMimeType.VIDEO_HEVC : media.CodecMimeType.VIDEO_AVC, 108 videoFrameWidth: videoProfile.size.width, 109 videoFrameHeight: videoProfile.size.height, 110 videoFrameRate: 30, 111 isHdr: isHdr 112 }; 113 let videoUri: string = `file://${context.filesDir}/${Date.now()}.mp4`; // Local sandbox path. 114 let file: fs.File = fs.openSync(videoUri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 115 let aVRecorderConfig: media.AVRecorderConfig = { 116 audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, 117 videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, 118 profile: aVRecorderProfile, 119 url: `fd://${file.fd.toString()}`, // Before passing in a file descriptor to this parameter, the file must be created by the caller and granted with the read and write permissions. Example value: fd://45--file:///data/media/01.mp4. 120 rotation: 0, // The value can be 0, 90, 180, or 270. If any other value is used, prepare() reports an error. 121 location: { latitude: 30, longitude: 130 } 122 }; 123 124 let avRecorder: media.AVRecorder | undefined = undefined; 125 try { 126 avRecorder = await media.createAVRecorder(); 127 } catch (error) { 128 let err = error as BusinessError; 129 console.error(`createAVRecorder call failed. error code: ${err.code}`); 130 } 131 132 if (avRecorder === undefined) { 133 return; 134 } 135 136 try { 137 await avRecorder.prepare(aVRecorderConfig); 138 } catch (error) { 139 let err = error as BusinessError; 140 console.error(`prepare call failed. error code: ${err.code}`); 141 } 142 143 let videoSurfaceId: string | undefined = undefined; // The surfaceID is passed in to the camera API to create a VideoOutput instance. 144 try { 145 videoSurfaceId = await avRecorder.getInputSurface(); 146 } catch (error) { 147 let err = error as BusinessError; 148 console.error(`getInputSurface call failed. error code: ${err.code}`); 149 } 150 if (videoSurfaceId === undefined) { 151 return; 152 } 153 // Create a VideoOutput instance. 154 let videoOutput: camera.VideoOutput | undefined = undefined; 155 try { 156 videoOutput = cameraManager.createVideoOutput(videoProfile, videoSurfaceId); 157 } catch (error) { 158 let err = error as BusinessError; 159 console.error(`Failed to create the videoOutput instance. error: ${err}`); 160 } 161 if (videoOutput === undefined) { 162 return; 163 } 164 // Listen for video output errors. 165 videoOutput.on('error', (error: BusinessError) => { 166 console.error(`Preview output error code: ${error.code}`); 167 }); 168 169 // Create a session. 170 let videoSession: camera.VideoSession | undefined = undefined; 171 try { 172 videoSession = cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO) as camera.VideoSession; 173 } catch (error) { 174 let err = error as BusinessError; 175 console.error(`Failed to create the session instance. error: ${err}`); 176 } 177 if (videoSession === undefined) { 178 return; 179 } 180 // Listen for session errors. 181 videoSession.on('error', (error: BusinessError) => { 182 console.error(`Video session error code: ${error.code}`); 183 }); 184 185 // Start configuration for the session. 186 try { 187 videoSession.beginConfig(); 188 } catch (error) { 189 let err = error as BusinessError; 190 console.error(`Failed to beginConfig. error: ${err}`); 191 } 192 193 // Create a camera input stream. 194 let cameraInput: camera.CameraInput | undefined = undefined; 195 try { 196 cameraInput = cameraManager.createCameraInput(cameraArray[0]); 197 } catch (error) { 198 let err = error as BusinessError; 199 console.error(`Failed to createCameraInput. error: ${err}`); 200 } 201 if (cameraInput === undefined) { 202 return; 203 } 204 // Listen for camera input errors. 205 let cameraDevice: camera.CameraDevice = cameraArray[0]; 206 cameraInput.on('error', cameraDevice, (error: BusinessError) => { 207 console.error(`Camera input error code: ${error.code}`); 208 }); 209 210 // Open the camera. 211 try { 212 await cameraInput.open(); 213 } catch (error) { 214 let err = error as BusinessError; 215 console.error(`Failed to open cameraInput. error: ${err}`); 216 } 217 218 // Add the camera input stream to the session. 219 try { 220 videoSession.addInput(cameraInput); 221 } catch (error) { 222 let err = error as BusinessError; 223 console.error(`Failed to add cameraInput. error: ${err}`); 224 } 225 226 // Create a preview output stream. For details about the surfaceId parameter, see the XComponent. The preview stream is the surface provided by the XComponent. 227 let previewOutput: camera.PreviewOutput | undefined = undefined; 228 let previewProfile = previewProfilesArray.find((previewProfile: camera.Profile) => { 229 return Math.abs((previewProfile.size.width / previewProfile.size.height) - (videoProfile.size.width / videoProfile.size.height)) < Number.EPSILON; 230 }); // Select the preview resolution with the same aspect ratio as the recording resolution. 231 if (previewProfile === undefined) { 232 return; 233 } 234 try { 235 previewOutput = cameraManager.createPreviewOutput(previewProfile, surfaceId); 236 } catch (error) { 237 let err = error as BusinessError; 238 console.error(`Failed to create the PreviewOutput instance. error: ${err}`); 239 } 240 if (previewOutput === undefined) { 241 return; 242 } 243 244 // Add the preview output stream to the session. 245 try { 246 videoSession.addOutput(previewOutput); 247 } catch (error) { 248 let err = error as BusinessError; 249 console.error(`Failed to add previewOutput. error: ${err}`); 250 } 251 252 // Add the video output stream to the session. 253 try { 254 videoSession.addOutput(videoOutput); 255 } catch (error) { 256 let err = error as BusinessError; 257 console.error(`Failed to add videoOutput. error: ${err}`); 258 } 259 260 // Commit the session configuration. 261 try { 262 await videoSession.commitConfig(); 263 } catch (error) { 264 let err = error as BusinessError; 265 console.error(`videoSession commitConfig error: ${err}`); 266 return; 267 } 268 269 // Start the session. 270 try { 271 await videoSession.start(); 272 } catch (error) { 273 let err = error as BusinessError; 274 console.error(`videoSession start error: ${err}`); 275 } 276 277 // Start the video output stream. 278 videoOutput.start((err: BusinessError) => { 279 if (err) { 280 console.error(`Failed to start the video output. error: ${err}`); 281 return; 282 } 283 console.info('Callback invoked to indicate the video output start success.'); 284 }); 285 286 // Start video recording. 287 try { 288 await avRecorder.start(); 289 } catch (error) { 290 let err = error as BusinessError; 291 console.error(`avRecorder start error: ${err}`); 292 } 293 294 // Stop the video output stream. 295 videoOutput.stop((err: BusinessError) => { 296 if (err) { 297 console.error(`Failed to stop the video output. error: ${err}`); 298 return; 299 } 300 console.info('Callback invoked to indicate the video output stop success.'); 301 }); 302 303 // Stop video recording. 304 try { 305 await avRecorder.stop(); 306 } catch (error) { 307 let err = error as BusinessError; 308 console.error(`avRecorder stop error: ${err}`); 309 } 310 311 // Stop the session. 312 await videoSession.stop(); 313 314 // Close the file. 315 fs.closeSync(file); 316 317 // Release the camera input stream. 318 await cameraInput.close(); 319 320 // Release the preview output stream. 321 await previewOutput.release(); 322 323 // Release the video output stream. 324 await videoOutput.release(); 325 326 // Release the session. 327 await videoSession.release(); 328 329 // Set the session to null. 330 videoSession = undefined; 331} 332``` 333