• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 录像实现方案
2
3## 开发流程
4
5在获取到相机支持的输出流能力后,开始创建录像流,开发流程如下。
6
7![Recording Development Process](figures/recording-development-process.png)
8
9
10## 完整示例
11[BaseContext获取方式](../reference/apis/js-apis-inner-application-baseContext.md)。
12```ts
13import camera from '@ohos.multimedia.camera';
14import { BusinessError } from '@ohos.base';
15import media from '@ohos.multimedia.media';
16import common from '@ohos.app.ability.common';
17
18async function videoRecording(baseContext: common.BaseContext, surfaceId: string): Promise<void> {
19  // 创建CameraManager对象
20  let cameraManager: camera.CameraManager = camera.getCameraManager(baseContext);
21  if (!cameraManager) {
22    console.error("camera.getCameraManager error");
23    return;
24  }
25
26  // 监听相机状态变化
27  cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
28    console.log(`camera : ${cameraStatusInfo.camera.cameraId}`);
29    console.log(`status: ${cameraStatusInfo.status}`);
30  });
31
32  // 获取相机列表
33  let cameraArray: Array<camera.CameraDevice> = [];
34  try {
35    cameraArray = cameraManager.getSupportedCameras();
36  } catch (error) {
37    let err = error as BusinessError;
38    console.error(`getSupportedCameras call failed. error code: ${err.code}`);
39  }
40
41  if (cameraArray.length <= 0) {
42    console.error("cameraManager.getSupportedCameras error")
43    return;
44  }
45
46  // 获取相机设备支持的输出流能力
47  let cameraOutputCap: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(cameraArray[0]);
48  if (!cameraOutputCap) {
49    console.error("cameraManager.getSupportedOutputCapability error")
50    return;
51  }
52  console.log("outputCapability: " + JSON.stringify(cameraOutputCap));
53
54  let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles;
55  if (!previewProfilesArray) {
56    console.error("createOutput previewProfilesArray == null || undefined");
57  }
58
59  let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles;
60  if (!photoProfilesArray) {
61    console.error("createOutput photoProfilesArray == null || undefined");
62  }
63
64  let videoProfilesArray: Array<camera.VideoProfile> = cameraOutputCap.videoProfiles;
65  if (!videoProfilesArray) {
66    console.error("createOutput videoProfilesArray == null || undefined");
67  }
68
69  let metadataObjectTypesArray: Array<camera.MetadataObjectType> = cameraOutputCap.supportedMetadataObjectTypes;
70  if (!metadataObjectTypesArray) {
71    console.error("createOutput metadataObjectTypesArray == null || undefined");
72  }
73
74  // 配置参数以实际硬件设备支持的范围为准
75  let aVRecorderProfile: media.AVRecorderProfile = {
76    audioBitrate: 48000,
77    audioChannels: 2,
78    audioCodec: media.CodecMimeType.AUDIO_AAC,
79    audioSampleRate: 48000,
80    fileFormat: media.ContainerFormatType.CFT_MPEG_4,
81    videoBitrate: 2000000,
82    videoCodec: media.CodecMimeType.VIDEO_MPEG4,
83    videoFrameWidth: 640,
84    videoFrameHeight: 480,
85    videoFrameRate: 30
86  };
87  let aVRecorderConfig: media.AVRecorderConfig = {
88    audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,
89    videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV,
90    profile: aVRecorderProfile,
91    url: 'fd://', // 文件需先由调用者创建,赋予读写权限,将文件fd传给此参数,eg.fd://45--file:///data/media/01.mp4
92    rotation: 0, // 合理值0、90、180、270,非合理值prepare接口将报错
93    location: { latitude: 30, longitude: 130 }
94  };
95
96  let avRecorder: media.AVRecorder | undefined = undefined;
97  try {
98    avRecorder = await media.createAVRecorder();
99  } catch (error) {
100    let err = error as BusinessError;
101    console.error(`createAVRecorder call failed. error code: ${err.code}`);
102  }
103
104  if (avRecorder === undefined) {
105    return;
106  }
107
108  try {
109    await avRecorder.prepare(aVRecorderConfig);
110  } catch (error) {
111    let err = error as BusinessError;
112    console.error(`prepare call failed. error code: ${err.code}`);
113  }
114
115  let videoSurfaceId: string | undefined = undefined; // 该surfaceID用于传递给相机接口创造videoOutput
116  try {
117    videoSurfaceId = await avRecorder.getInputSurface();
118  } catch (error) {
119    let err = error as BusinessError;
120    console.error(`getInputSurface call failed. error code: ${err.code}`);
121  }
122  if (videoSurfaceId === undefined) {
123    return;
124  }
125  // 创建VideoOutput对象
126  let videoOutput: camera.VideoOutput | undefined = undefined;
127  try {
128    videoOutput = cameraManager.createVideoOutput(videoProfilesArray[0], videoSurfaceId);
129  } catch (error) {
130    let err = error as BusinessError;
131    console.error(`Failed to create the videoOutput instance. error: ${JSON.stringify(err)}`);
132  }
133  if (videoOutput === undefined) {
134    return;
135  }
136  // 监听视频输出错误信息
137  videoOutput.on('error', (error: BusinessError) => {
138    console.log(`Preview output error code: ${error.code}`);
139  });
140
141  //创建会话
142  let captureSession: camera.CaptureSession | undefined = undefined;
143  try {
144    captureSession = cameraManager.createCaptureSession();
145  } catch (error) {
146    let err = error as BusinessError;
147    console.error(`Failed to create the CaptureSession instance. error: ${JSON.stringify(err)}`);
148  }
149  if (captureSession === undefined) {
150    return;
151  }
152  // 监听session错误信息
153  captureSession.on('error', (error: BusinessError) => {
154    console.log(`Capture session error code: ${error.code}`);
155  });
156
157  // 开始配置会话
158  try {
159    captureSession.beginConfig();
160  } catch (error) {
161    let err = error as BusinessError;
162    console.error(`Failed to beginConfig. error: ${JSON.stringify(err)}`);
163  }
164
165  // 创建相机输入流
166  let cameraInput: camera.CameraInput | undefined = undefined;
167  try {
168    cameraInput = cameraManager.createCameraInput(cameraArray[0]);
169  } catch (error) {
170    let err = error as BusinessError;
171    console.error(`Failed to createCameraInput. error: ${JSON.stringify(err)}`);
172  }
173  if (cameraInput === undefined) {
174    return;
175  }
176  // 监听cameraInput错误信息
177  let cameraDevice: camera.CameraDevice = cameraArray[0];
178  cameraInput.on('error', cameraDevice, (error: BusinessError) => {
179    console.log(`Camera input error code: ${error.code}`);
180  });
181
182  // 打开相机
183  try {
184    await cameraInput.open();
185  } catch (error) {
186    let err = error as BusinessError;
187    console.error(`Failed to open cameraInput. error: ${JSON.stringify(err)}`);
188  }
189
190  // 向会话中添加相机输入流
191  try {
192    captureSession.addInput(cameraInput);
193  } catch (error) {
194    let err = error as BusinessError;
195    console.error(`Failed to add cameraInput. error: ${JSON.stringify(err)}`);
196  }
197
198  // 创建预览输出流,其中参数 surfaceId 参考下面 XComponent 组件,预览流为XComponent组件提供的surface
199  let previewOutput: camera.PreviewOutput | undefined = undefined;
200  try {
201    previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId);
202  } catch (error) {
203    let err = error as BusinessError;
204    console.error(`Failed to create the PreviewOutput instance. error: ${JSON.stringify(err)}`);
205  }
206
207  if (previewOutput === undefined) {
208    return;
209  }
210  // 向会话中添加预览输入流
211  try {
212    captureSession.addOutput(previewOutput);
213  } catch (error) {
214    let err = error as BusinessError;
215    console.error(`Failed to add previewOutput. error: ${JSON.stringify(err)}`);
216  }
217
218  // 向会话中添加录像输出流
219  try {
220    captureSession.addOutput(videoOutput);
221  } catch (error) {
222    let err = error as BusinessError;
223    console.error(`Failed to add videoOutput. error: ${JSON.stringify(err)}`);
224  }
225
226  // 提交会话配置
227  try {
228    await captureSession.commitConfig();
229  } catch (error) {
230    let err = error as BusinessError;
231    console.error(`captureSession commitConfig error: ${JSON.stringify(err)}`);
232  }
233
234  // 启动会话
235  try {
236    await captureSession.start();
237  } catch (error) {
238    let err = error as BusinessError;
239    console.error(`captureSession start error: ${JSON.stringify(err)}`);
240  }
241
242  // 启动录像输出流
243  videoOutput.start((err: BusinessError) => {
244    if (err) {
245      console.error(`Failed to start the video output. error: ${JSON.stringify(err)}`);
246      return;
247    }
248    console.log('Callback invoked to indicate the video output start success.');
249  });
250
251  // 开始录像
252  try {
253    await avRecorder.start();
254  } catch (error) {
255    let err = error as BusinessError;
256    console.error(`avRecorder start error: ${JSON.stringify(err)}`);
257  }
258
259  // 停止录像输出流
260  videoOutput.stop((err: BusinessError) => {
261    if (err) {
262      console.error(`Failed to stop the video output. error: ${JSON.stringify(err)}`);
263      return;
264    }
265    console.log('Callback invoked to indicate the video output stop success.');
266  });
267
268  // 停止录像
269  try {
270    await avRecorder.stop();
271  } catch (error) {
272    let err = error as BusinessError;
273    console.error(`avRecorder stop error: ${JSON.stringify(err)}`);
274  }
275
276  // 停止当前会话
277  captureSession.stop();
278
279  // 释放相机输入流
280  cameraInput.close();
281
282  // 释放预览输出流
283  previewOutput.release();
284
285  // 释放录像输出流
286  videoOutput.release();
287
288  // 释放会话
289  captureSession.release();
290
291  // 会话置空
292  captureSession = undefined;
293}
294```
295