• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![Recording Development Process](figures/recording-development-process.png)
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