video-recorder.md 6.7 KB
Newer Older
W
wusongqing 已提交
1
# 视频录制开发指导
W
wusongqing 已提交
2

3
## 简介
W
wusongqing 已提交
4

5
视频录制的主要工作是捕获音视频信号,完成音视频编码并保存到文件中,帮助开发者轻松实现音视频录制功能,包括开始录制、暂停录制、恢复录制、停止录制、释放资源等功能控制。它允许调用者指定录制的编码格式、封装格式、文件路径等参数。
W
wusongqing 已提交
6

7 8 9 10 11
## 运作机制

该模块提供了视频录制状态变化示意图和视频录制外部模块交互图。

**图1** 视频录制状态变化示意图
W
wusongqing 已提交
12

W
wusongqing 已提交
13
![zh-ch_image_video_recorder_state_machine](figures/zh-ch_image_video_recorder_state_machine.png)
W
wusongqing 已提交
14

15
**图2** 视频录制外部模块交互图
W
wusongqing 已提交
16

W
wusongqing 已提交
17
![zh-ch_image_video_recorder_zero](figures/zh-ch_image_video_recorder_zero.png)
W
wusongqing 已提交
18

19
**说明**:三方相机应用或系统相机通过调用JS接口层提供的js接口实现相应功能时,框架层会通过Native Framework的媒体服务,调用音频部件通过音频HDI捕获的音频数据,再通过软件编码输出编码封装后的音频数据保存至文件中,和图形子系统通过视频HDI捕获的图像数据,再通过视频编码HDI编码,将编码后的图像数据保存至文件中,实现视频录制功能。
20 21 22 23 24 25

## 约束与限制

开发者在进行录制功能开发前,需要先对所开发的应用配置麦克风权限(ohos.permission.MICROPHONE)和相机权限(ohos.permission.CAMERA),权限配置相关内容可参考:[访问控制权限申请指导](../security/accesstoken-guidelines.md)

## 开发指导
W
wusongqing 已提交
26

27
详细API含义可参考:[媒体服务API文档VideoRecorder](../reference/apis/js-apis-media.md#videorecorder9)
W
wusongqing 已提交
28

W
wusongqing 已提交
29
### 全流程场景
W
wusongqing 已提交
30

31
视频录制全流程场景包含:创建实例、设置录制参数、开始录制、暂停录制、恢复录制、停止录制、释放资源等流程。
W
wusongqing 已提交
32 33

```js
34 35
import media from '@ohos.multimedia.media'
import mediaLibrary from '@ohos.multimedia.mediaLibrary'
36 37
export class VideoRecorderDemo {
  private testFdNumber; // 用于保存fd地址
38
  // pathName是传入的录制文件名,例如:01.mp4,生成后的文件地址:/storage/media/100/local/files/Video/01.mp4
39 40
  // 使用mediaLibrary需要添加以下权限, ohos.permission.MEDIA_LOCATION、ohos.permission.WRITE_MEDIA、ohos.permission.READ_MEDIA
  async getFd(pathName) {
41 42 43 44 45 46 47
    let displayName = pathName;
    const mediaTest = mediaLibrary.getMediaLibrary();
    let fileKeyObj = mediaLibrary.FileKey;
    let mediaType = mediaLibrary.MediaType.VIDEO;
    let publicPath = await mediaTest.getPublicDirectory(mediaLibrary.DirectoryType.DIR_VIDEO);
    let dataUri = await mediaTest.createAsset(mediaType, displayName, publicPath);
    if (dataUri != undefined) {
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
      let args = dataUri.id.toString();
      let fetchOp = {
        selections : fileKeyObj.ID + "=?",
        selectionArgs : [args],
      }
      let fetchFileResult = await mediaTest.getFileAssets(fetchOp);
      let fileAsset = await fetchFileResult.getAllObject();
      let fdNumber = await fileAsset[0].open('Rw');
      this.testFdNumber = "fd://" + fdNumber.toString();
    }
  }

  // 当发生错误上上报的错误回调接口
  failureCallback(error) {
      console.info('error happened, error name is ' + error.name);
      console.info('error happened, error code is ' + error.code);
      console.info('error happened, error message is ' + error.message);
  }

  // 当发生异常时,系统调用的错误回调接口
  catchCallback(error) {
      console.info('catch error happened, error name is ' + error.name);
      console.info('catch error happened, error code is ' + error.code);
      console.info('catch error happened, error message is ' + error.message);
  }

  async videoRecorderDemo() {
    let videoRecorder = null; // videoRecorder空对象在createVideoRecorder成功后赋值
    let surfaceID = null; // 用于保存getInputSurface返回的surfaceID
    // 获取需要录制的视频的fd地址
    await this.getFd('01.mp4');
79
    // 录制相关参数配置,配置参数以实际硬件设备支持的范围为准
80 81 82 83 84 85
    let videoProfile = {
      audioBitrate : 48000,
      audioChannels : 2,
      audioCodec : 'audio/mp4a-latm',
      audioSampleRate : 48000,
      fileFormat : 'mp4',
86
      videoBitrate : 2000000,
87 88 89 90
      videoCodec : 'video/mp4v-es',
      videoFrameWidth : 640,
      videoFrameHeight : 480,
      videoFrameRate : 30
91
    }
W
wusongqing 已提交
92

93 94 95 96 97 98
    let videoConfig = {
      audioSourceType : 1,
      videoSourceType : 0,
      profile : videoProfile,
      url : this.testFdNumber, // testFdNumber由getFd生成
      orientationHint : 0,
99
      location : { latitude : 30, longitude : 130 }
100 101 102 103 104
    }
    // 创建videoRecorder对象
    await media.createVideoRecorder().then((recorder) => {
      console.info('case createVideoRecorder called');
      if (typeof (recorder) != 'undefined') {
W
wusongqing 已提交
105 106
        videoRecorder = recorder;
        console.info('createVideoRecorder success');
107
      } else {
W
wusongqing 已提交
108
        console.info('createVideoRecorder failed');
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
      }
    }, this.failureCallback).catch(this.catchCallback);

    // 调用prepare完成视频录制前的准备工作
    await videoRecorder.prepare(videoConfig).then(() => {
      console.info('prepare success');
    }, this.failureCallback).catch(this.catchCallback);

    // 获取surfaceID并保存下来传递给camera相关接口
    await videoRecorder.getInputSurface().then((surface) => {
      console.info('getInputSurface success');
      surfaceID = surface;
    }, this.failureCallback).catch(this.catchCallback);

    // 视频录制依赖相机相关接口,以下需要先调用相机起流接口后才能继续执行,具体的相机接口调用请参考sample用例
    // 视频录制启动接口
    await videoRecorder.start().then(() => {
      console.info('start success');
    }, this.failureCallback).catch(this.catchCallback);

    // 调用pause接口时需要暂停camera出流
    await videoRecorder.pause().then(() => {
      console.info('pause success');
    }, this.failureCallback).catch(this.catchCallback);

    // 调用resume接口时需要恢复camera出流
    await videoRecorder.resume().then(() => {
      console.info('resume success');
    }, this.failureCallback).catch(this.catchCallback);

    // 停止camera出流后,停止视频录制
    await videoRecorder.stop().then(() => {
      console.info('stop success');
    }, this.failureCallback).catch(this.catchCallback);

    // 重置录制相关配置
    await videoRecorder.reset().then(() => {
      console.info('reset success');
    }, this.failureCallback).catch(this.catchCallback);

    // 释放视频录制相关资源并释放camera对象相关资源
    await videoRecorder.release().then(() => {
      console.info('release success');
    }, this.failureCallback).catch(this.catchCallback);

    // 相关对象置null
    videoRecorder = undefined;
    surfaceID = undefined;
  }
}
Mr-YX's avatar
Mr-YX 已提交
159
```