• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 视频录制开发指导
2
3## 简介
4
5视频录制的主要工作是捕获音视频信号,完成音视频编码并保存到文件中,帮助开发者轻松实现音视频录制功能,包括开始录制、暂停录制、恢复录制、停止录制、释放资源等功能控制。它允许调用者指定录制的编码格式、封装格式、文件路径等参数。
6
7## 运作机制
8
9该模块提供了视频录制状态变化示意图和视频录制外部模块交互图。
10
11**图1** 视频录制状态变化示意图
12
13![zh-ch_image_video_recorder_state_machine](figures/zh-ch_image_video_recorder_state_machine.png)
14
15**图2** 视频录制外部模块交互图
16
17![zh-ch_image_video_recorder_zero](figures/zh-ch_image_video_recorder_zero.png)
18
19**说明**:三方相机应用或系统相机通过调用JS接口层提供的js接口实现相应功能时,框架层会通过Native Framework的媒体服务,调用音频部件通过音频HDI捕获的音频数据,再通过软件编码输出编码封装后的音频数据保存至文件中,和图形子系统通过视频HDI捕获的图像数据,再通过视频编码HDI编码,将编码后的图像数据保存至文件中,实现视频录制功能。
20
21## 约束与限制
22
23开发者在进行录制功能开发前,需要先对所开发的应用配置麦克风权限(ohos.permission.MICROPHONE)和相机权限(ohos.permission.CAMERA),权限配置相关内容可参考:[访问控制权限申请指导](../security/accesstoken-guidelines.md)
24
25## 开发指导
26
27详细API含义可参考:[媒体服务API文档VideoRecorder](../reference/apis/js-apis-media.md#videorecorder9)
28
29### 全流程场景
30
31视频录制全流程场景包含:创建实例、设置录制参数、开始录制、暂停录制、恢复录制、停止录制、释放资源等流程。
32
33```js
34import media from '@ohos.multimedia.media'
35import mediaLibrary from '@ohos.multimedia.mediaLibrary'
36export class VideoRecorderDemo {
37  private testFdNumber; // 用于保存fd地址
38  // pathName是传入的录制文件名,例如:01.mp4,生成后的文件地址:/storage/media/100/local/files/Video/01.mp4
39  // 使用mediaLibrary需要添加以下权限, ohos.permission.MEDIA_LOCATIONohos.permission.WRITE_MEDIAohos.permission.READ_MEDIA
40  async getFd(pathName) {
41    let displayName = pathName;
42    const mediaTest = mediaLibrary.getMediaLibrary();
43    let fileKeyObj = mediaLibrary.FileKey;
44    let mediaType = mediaLibrary.MediaType.VIDEO;
45    let publicPath = await mediaTest.getPublicDirectory(mediaLibrary.DirectoryType.DIR_VIDEO);
46    let dataUri = await mediaTest.createAsset(mediaType, displayName, publicPath);
47    if (dataUri != undefined) {
48      let args = dataUri.id.toString();
49      let fetchOp = {
50        selections : fileKeyObj.ID + "=?",
51        selectionArgs : [args],
52      }
53      let fetchFileResult = await mediaTest.getFileAssets(fetchOp);
54      let fileAsset = await fetchFileResult.getAllObject();
55      let fdNumber = await fileAsset[0].open('Rw');
56      this.testFdNumber = "fd://" + fdNumber.toString();
57    }
58  }
59
60  // 当发生错误上上报的错误回调接口
61  failureCallback(error) {
62      console.info('error happened, error name is ' + error.name);
63      console.info('error happened, error code is ' + error.code);
64      console.info('error happened, error message is ' + error.message);
65  }
66
67  // 当发生异常时,系统调用的错误回调接口
68  catchCallback(error) {
69      console.info('catch error happened, error name is ' + error.name);
70      console.info('catch error happened, error code is ' + error.code);
71      console.info('catch error happened, error message is ' + error.message);
72  }
73
74  async videoRecorderDemo() {
75    let videoRecorder = null; // videoRecorder空对象在createVideoRecorder成功后赋值
76    let surfaceID = null; // 用于保存getInputSurface返回的surfaceID
77    // 获取需要录制的视频的fd地址
78    await this.getFd('01.mp4');
79    // 录制相关参数配置,配置参数以实际硬件设备支持的范围为准
80    let videoProfile = {
81      audioBitrate : 48000,
82      audioChannels : 2,
83      audioCodec : 'audio/mp4a-latm',
84      audioSampleRate : 48000,
85      fileFormat : 'mp4',
86      videoBitrate : 2000000,
87      videoCodec : 'video/avc',
88      videoFrameWidth : 640,
89      videoFrameHeight : 480,
90      videoFrameRate : 30
91    }
92
93    let videoConfig = {
94      audioSourceType : 1,
95      videoSourceType : 0,
96      profile : videoProfile,
97      url : this.testFdNumber, // testFdNumber由getFd生成
98      orientationHint : 0,
99      location : { latitude : 30, longitude : 130 }
100    }
101    // 创建videoRecorder对象
102    await media.createVideoRecorder().then((recorder) => {
103      console.info('case createVideoRecorder called');
104      if (typeof (recorder) != 'undefined') {
105        videoRecorder = recorder;
106        console.info('createVideoRecorder success');
107      } else {
108        console.info('createVideoRecorder failed');
109      }
110    }, this.failureCallback).catch(this.catchCallback);
111
112    // 调用prepare完成视频录制前的准备工作
113    await videoRecorder.prepare(videoConfig).then(() => {
114      console.info('prepare success');
115    }, this.failureCallback).catch(this.catchCallback);
116
117    // 获取surfaceID并保存下来传递给camera相关接口
118    await videoRecorder.getInputSurface().then((surface) => {
119      console.info('getInputSurface success');
120      surfaceID = surface;
121    }, this.failureCallback).catch(this.catchCallback);
122
123    // 视频录制依赖相机相关接口,以下需要先调用相机起流接口后才能继续执行,具体的相机接口调用请参考sample用例
124    // 视频录制启动接口
125    await videoRecorder.start().then(() => {
126      console.info('start success');
127    }, this.failureCallback).catch(this.catchCallback);
128
129    // 调用pause接口时需要暂停camera出流
130    await videoRecorder.pause().then(() => {
131      console.info('pause success');
132    }, this.failureCallback).catch(this.catchCallback);
133
134    // 调用resume接口时需要恢复camera出流
135    await videoRecorder.resume().then(() => {
136      console.info('resume success');
137    }, this.failureCallback).catch(this.catchCallback);
138
139    // 停止camera出流后,停止视频录制
140    await videoRecorder.stop().then(() => {
141      console.info('stop success');
142    }, this.failureCallback).catch(this.catchCallback);
143
144    // 重置录制相关配置
145    await videoRecorder.reset().then(() => {
146      console.info('reset success');
147    }, this.failureCallback).catch(this.catchCallback);
148
149    // 释放视频录制相关资源并释放camera对象相关资源
150    await videoRecorder.release().then(() => {
151      console.info('release success');
152    }, this.failureCallback).catch(this.catchCallback);
153
154    // 相关对象置null
155    videoRecorder = undefined;
156    surfaceID = undefined;
157  }
158}
159```