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