1e41f4b71Sopenharmony_ci# Camera Recording (ArkTS) 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ciAs another important function of the camera application, video recording is the process of cyclic frame capture. To smooth video recording, you can follow step 4 in [Camera Photographing](camera-shooting.md) to set the resolution, flash, focal length, photo quality, and rotation angle. 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci## How to Develop 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciRead [Camera](../../reference/apis-camera-kit/js-apis-camera.md) for the API reference. 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci1. Import the media module. The [APIs](../../reference/apis-media-kit/js-apis-media.md) provided by this module are used to obtain the surface ID and create a video output stream. 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci ```ts 12e41f4b71Sopenharmony_ci import { BusinessError } from '@kit.BasicServicesKit'; 13e41f4b71Sopenharmony_ci import { camera } from '@kit.CameraKit'; 14e41f4b71Sopenharmony_ci import { media } from '@kit.MediaKit'; 15e41f4b71Sopenharmony_ci ``` 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ci2. Create a surface. 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ci Call **createAVRecorder()** of the media module to create an **AVRecorder** instance, and call [getInputSurface](../../reference/apis-media-kit/js-apis-media.md#getinputsurface9) of the instance to obtain the surface ID, which is associated with the video output stream to process the stream data. 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci ```ts 22e41f4b71Sopenharmony_ci async function getVideoSurfaceId(aVRecorderConfig: media.AVRecorderConfig): Promise<string | undefined> { // For details about aVRecorderConfig, see the next section. 23e41f4b71Sopenharmony_ci let avRecorder: media.AVRecorder | undefined = undefined; 24e41f4b71Sopenharmony_ci try { 25e41f4b71Sopenharmony_ci avRecorder = await media.createAVRecorder(); 26e41f4b71Sopenharmony_ci } catch (error) { 27e41f4b71Sopenharmony_ci let err = error as BusinessError; 28e41f4b71Sopenharmony_ci console.error(`createAVRecorder call failed. error code: ${err.code}`); 29e41f4b71Sopenharmony_ci } 30e41f4b71Sopenharmony_ci if (avRecorder === undefined) { 31e41f4b71Sopenharmony_ci return undefined; 32e41f4b71Sopenharmony_ci } 33e41f4b71Sopenharmony_ci avRecorder.prepare(aVRecorderConfig, (err: BusinessError) => { 34e41f4b71Sopenharmony_ci if (err == null) { 35e41f4b71Sopenharmony_ci console.info('prepare success'); 36e41f4b71Sopenharmony_ci } else { 37e41f4b71Sopenharmony_ci console.error('prepare failed and error is ' + err.message); 38e41f4b71Sopenharmony_ci } 39e41f4b71Sopenharmony_ci }); 40e41f4b71Sopenharmony_ci let videoSurfaceId = await avRecorder.getInputSurface(); 41e41f4b71Sopenharmony_ci return videoSurfaceId; 42e41f4b71Sopenharmony_ci } 43e41f4b71Sopenharmony_ci ``` 44e41f4b71Sopenharmony_ci 45e41f4b71Sopenharmony_ci3. Create a video output stream. 46e41f4b71Sopenharmony_ci 47e41f4b71Sopenharmony_ci Obtain the video output streams supported by the current device from **videoProfiles** in the [CameraOutputCapability](../../reference/apis-camera-kit/js-apis-camera.md#cameraoutputcapability) class. Then, define video recording parameters and use [createVideoOutput](../../reference/apis-camera-kit/js-apis-camera.md#createvideooutput) to create a video output stream. 48e41f4b71Sopenharmony_ci 49e41f4b71Sopenharmony_ci > **NOTE** 50e41f4b71Sopenharmony_ci > The preview stream and video output stream must have the same aspect ratio of the resolution. For example, the aspect ratio in the code snippet below is 640:480 (which is equal to 4:3), then the aspect ratio of the resolution of the preview stream must also be 4:3. This means that the resolution can be 640:480, 960:720, 1440:1080, or the like. 51e41f4b71Sopenharmony_ci 52e41f4b71Sopenharmony_ci ```ts 53e41f4b71Sopenharmony_ci async function getVideoOutput(cameraManager: camera.CameraManager, videoSurfaceId: string, cameraOutputCapability: camera.CameraOutputCapability): Promise<camera.VideoOutput | undefined> { 54e41f4b71Sopenharmony_ci let videoProfilesArray: Array<camera.VideoProfile> = cameraOutputCapability.videoProfiles; 55e41f4b71Sopenharmony_ci if (!videoProfilesArray) { 56e41f4b71Sopenharmony_ci console.error("createOutput videoProfilesArray == null || undefined"); 57e41f4b71Sopenharmony_ci return undefined; 58e41f4b71Sopenharmony_ci } 59e41f4b71Sopenharmony_ci // AVRecorderProfile 60e41f4b71Sopenharmony_ci let aVRecorderProfile: media.AVRecorderProfile = { 61e41f4b71Sopenharmony_ci fileFormat: media.ContainerFormatType.CFT_MPEG_4, // Video file container format. Only MP4 is supported. 62e41f4b71Sopenharmony_ci videoBitrate: 100000, // Video bit rate. 63e41f4b71Sopenharmony_ci videoCodec: media.CodecMimeType.VIDEO_AVC, // Video file encoding format. AVC is supported. 64e41f4b71Sopenharmony_ci videoFrameWidth: 640, // Video frame width. 65e41f4b71Sopenharmony_ci videoFrameHeight: 480, // Video frame height. 66e41f4b71Sopenharmony_ci videoFrameRate: 30 // Video frame rate. 67e41f4b71Sopenharmony_ci }; 68e41f4b71Sopenharmony_ci // Define video recording parameters. The ratio of the resolution width (videoFrameWidth) to the resolution height (videoFrameHeight) of the video output stream must be the same as that of the preview stream. 69e41f4b71Sopenharmony_ci let aVRecorderConfig: media.AVRecorderConfig = { 70e41f4b71Sopenharmony_ci videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, 71e41f4b71Sopenharmony_ci profile: aVRecorderProfile, 72e41f4b71Sopenharmony_ci url: 'fd://35', 73e41f4b71Sopenharmony_ci rotation: 90 // 90° is the default vertical display angle. You can use other values based on project requirements. 74e41f4b71Sopenharmony_ci }; 75e41f4b71Sopenharmony_ci // Create an AVRecorder instance. 76e41f4b71Sopenharmony_ci let avRecorder: media.AVRecorder | undefined = undefined; 77e41f4b71Sopenharmony_ci try { 78e41f4b71Sopenharmony_ci avRecorder = await media.createAVRecorder(); 79e41f4b71Sopenharmony_ci } catch (error) { 80e41f4b71Sopenharmony_ci let err = error as BusinessError; 81e41f4b71Sopenharmony_ci console.error(`createAVRecorder call failed. error code: ${err.code}`); 82e41f4b71Sopenharmony_ci } 83e41f4b71Sopenharmony_ci if (avRecorder === undefined) { 84e41f4b71Sopenharmony_ci return undefined; 85e41f4b71Sopenharmony_ci } 86e41f4b71Sopenharmony_ci // Set video recording parameters. 87e41f4b71Sopenharmony_ci avRecorder.prepare(aVRecorderConfig); 88e41f4b71Sopenharmony_ci // Create a VideoOutput instance. 89e41f4b71Sopenharmony_ci let videoOutput: camera.VideoOutput | undefined = undefined; 90e41f4b71Sopenharmony_ci // The width and height of the videoProfile object passed in by createVideoOutput must be the same as those of aVRecorderProfile. 91e41f4b71Sopenharmony_ci let videoProfile: undefined | camera.VideoProfile = videoProfilesArray.find((profile: camera.VideoProfile) => { 92e41f4b71Sopenharmony_ci return profile.size.width === aVRecorderProfile.videoFrameWidth && profile.size.height === aVRecorderProfile.videoFrameHeight; 93e41f4b71Sopenharmony_ci }); 94e41f4b71Sopenharmony_ci if (!videoProfile) { 95e41f4b71Sopenharmony_ci console.error('videoProfile is not found'); 96e41f4b71Sopenharmony_ci return; 97e41f4b71Sopenharmony_ci } 98e41f4b71Sopenharmony_ci try { 99e41f4b71Sopenharmony_ci videoOutput = cameraManager.createVideoOutput(videoProfile, videoSurfaceId); 100e41f4b71Sopenharmony_ci } catch (error) { 101e41f4b71Sopenharmony_ci let err = error as BusinessError; 102e41f4b71Sopenharmony_ci console.error('Failed to create the videoOutput instance. errorCode = ' + err.code); 103e41f4b71Sopenharmony_ci } 104e41f4b71Sopenharmony_ci return videoOutput; 105e41f4b71Sopenharmony_ci } 106e41f4b71Sopenharmony_ci ``` 107e41f4b71Sopenharmony_ci 108e41f4b71Sopenharmony_ci4. Start video recording. 109e41f4b71Sopenharmony_ci 110e41f4b71Sopenharmony_ci Call [start](../../reference/apis-camera-kit/js-apis-camera.md#start-1) of the **VideoOutput** instance to start the video output stream, and then call [start](../../reference/apis-media-kit/js-apis-media.md#start9) of the **AVRecorder** instance to start recording. 111e41f4b71Sopenharmony_ci 112e41f4b71Sopenharmony_ci ```ts 113e41f4b71Sopenharmony_ci async function startVideo(videoOutput: camera.VideoOutput, avRecorder: media.AVRecorder): Promise<void> { 114e41f4b71Sopenharmony_ci videoOutput.start(async (err: BusinessError) => { 115e41f4b71Sopenharmony_ci if (err) { 116e41f4b71Sopenharmony_ci console.error(`Failed to start the video output ${err.message}`); 117e41f4b71Sopenharmony_ci return; 118e41f4b71Sopenharmony_ci } 119e41f4b71Sopenharmony_ci console.info('Callback invoked to indicate the video output start success.'); 120e41f4b71Sopenharmony_ci }); 121e41f4b71Sopenharmony_ci try { 122e41f4b71Sopenharmony_ci await avRecorder.start(); 123e41f4b71Sopenharmony_ci } catch (error) { 124e41f4b71Sopenharmony_ci let err = error as BusinessError; 125e41f4b71Sopenharmony_ci console.error(`avRecorder start error: ${JSON.stringify(err)}`); 126e41f4b71Sopenharmony_ci } 127e41f4b71Sopenharmony_ci } 128e41f4b71Sopenharmony_ci ``` 129e41f4b71Sopenharmony_ci 130e41f4b71Sopenharmony_ci5. Stop video recording. 131e41f4b71Sopenharmony_ci 132e41f4b71Sopenharmony_ci Call [stop](../../reference/apis-media-kit/js-apis-media.md#stop9-3) of the **AVRecorder** instance to stop recording, and then call [stop](../../reference/apis-camera-kit/js-apis-camera.md#stop-1) of the **VideoOutput** instance to stop the video output stream. 133e41f4b71Sopenharmony_ci 134e41f4b71Sopenharmony_ci ```ts 135e41f4b71Sopenharmony_ci async function stopVideo(videoOutput: camera.VideoOutput, avRecorder: media.AVRecorder): Promise<void> { 136e41f4b71Sopenharmony_ci try { 137e41f4b71Sopenharmony_ci await avRecorder.stop(); 138e41f4b71Sopenharmony_ci } catch (error) { 139e41f4b71Sopenharmony_ci let err = error as BusinessError; 140e41f4b71Sopenharmony_ci console.error(`avRecorder stop error: ${JSON.stringify(err)}`); 141e41f4b71Sopenharmony_ci } 142e41f4b71Sopenharmony_ci videoOutput.stop((err: BusinessError) => { 143e41f4b71Sopenharmony_ci if (err) { 144e41f4b71Sopenharmony_ci console.error(`Failed to stop the video output ${err.message}`); 145e41f4b71Sopenharmony_ci return; 146e41f4b71Sopenharmony_ci } 147e41f4b71Sopenharmony_ci console.info('Callback invoked to indicate the video output stop success.'); 148e41f4b71Sopenharmony_ci }); 149e41f4b71Sopenharmony_ci } 150e41f4b71Sopenharmony_ci ``` 151e41f4b71Sopenharmony_ci 152e41f4b71Sopenharmony_ci 153e41f4b71Sopenharmony_ci## Status Listening 154e41f4b71Sopenharmony_ci 155e41f4b71Sopenharmony_ciDuring camera application development, you can listen for the status of the video output stream, including recording start, recording end, and video output errors. 156e41f4b71Sopenharmony_ci 157e41f4b71Sopenharmony_ci- Register the **'frameStart'** event to listen for recording start events. This event can be registered when a **VideoOutput** instance is created and is triggered when the bottom layer starts exposure for recording for the first time. Video recording starts as long as a result is returned. 158e41f4b71Sopenharmony_ci 159e41f4b71Sopenharmony_ci ```ts 160e41f4b71Sopenharmony_ci function onVideoOutputFrameStart(videoOutput: camera.VideoOutput): void { 161e41f4b71Sopenharmony_ci videoOutput.on('frameStart', (err: BusinessError) => { 162e41f4b71Sopenharmony_ci if (err !== undefined && err.code !== 0) { 163e41f4b71Sopenharmony_ci return; 164e41f4b71Sopenharmony_ci } 165e41f4b71Sopenharmony_ci console.info('Video frame started'); 166e41f4b71Sopenharmony_ci }); 167e41f4b71Sopenharmony_ci } 168e41f4b71Sopenharmony_ci ``` 169e41f4b71Sopenharmony_ci 170e41f4b71Sopenharmony_ci- Register the **'frameEnd'** event to listen for recording end events. This event can be registered when a **VideoOutput** instance is created and is triggered when the last frame of recording ends. Video recording ends as long as a result is returned. 171e41f4b71Sopenharmony_ci 172e41f4b71Sopenharmony_ci ```ts 173e41f4b71Sopenharmony_ci function onVideoOutputFrameEnd(videoOutput: camera.VideoOutput): void { 174e41f4b71Sopenharmony_ci videoOutput.on('frameEnd', (err: BusinessError) => { 175e41f4b71Sopenharmony_ci if (err !== undefined && err.code !== 0) { 176e41f4b71Sopenharmony_ci return; 177e41f4b71Sopenharmony_ci } 178e41f4b71Sopenharmony_ci console.info('Video frame ended'); 179e41f4b71Sopenharmony_ci }); 180e41f4b71Sopenharmony_ci } 181e41f4b71Sopenharmony_ci ``` 182e41f4b71Sopenharmony_ci 183e41f4b71Sopenharmony_ci- Register the **'error'** event to listen for video output errors. The callback function returns an error code when an API is incorrectly used. For details about the error code types, see [CameraErrorCode](../../reference/apis-camera-kit/js-apis-camera.md#cameraerrorcode). 184e41f4b71Sopenharmony_ci 185e41f4b71Sopenharmony_ci ```ts 186e41f4b71Sopenharmony_ci function onVideoOutputError(videoOutput: camera.VideoOutput): void { 187e41f4b71Sopenharmony_ci videoOutput.on('error', (error: BusinessError) => { 188e41f4b71Sopenharmony_ci console.error(`Video output error code: ${error.code}`); 189e41f4b71Sopenharmony_ci }); 190e41f4b71Sopenharmony_ci } 191e41f4b71Sopenharmony_ci ``` 192