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