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