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

W
wusongqing 已提交
3
## 场景介绍
W
wusongqing 已提交
4

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

W
wusongqing 已提交
7
**图1** 视频录制状态机
W
wusongqing 已提交
8

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

W
wusongqing 已提交
11
**图2** 视频录制零层图
W
wusongqing 已提交
12

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

W
wusongqing 已提交
15
## 开发步骤
W
wusongqing 已提交
16

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

W
wusongqing 已提交
19
### 全流程场景
W
wusongqing 已提交
20

Mr-YX's avatar
Mr-YX 已提交
21
包含流程:创建实例、设置录制参数、录制视频、暂停录制、恢复录制、停止录制、释放资源等流程。
W
wusongqing 已提交
22 23

```js
24 25
import media from '@ohos.multimedia.media'
import mediaLibrary from '@ohos.multimedia.mediaLibrary'
26 27
export class VideoRecorderDemo {
  private testFdNumber; // 用于保存fd地址
28
  // pathName是传入的录制文件名,例如:01.mp4,生成后的文件地址:/storage/media/100/local/files/Video/01.mp4
29 30
  // 使用mediaLibrary需要添加以下权限, ohos.permission.MEDIA_LOCATION、ohos.permission.WRITE_MEDIA、ohos.permission.READ_MEDIA
  async getFd(pathName) {
31 32 33 34 35 36 37
    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) {
38 39 40 41 42 43 44 45 46 47 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 79 80
      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');
    // 录制相关参数配置
    let videoProfile = {
      audioBitrate : 48000,
      audioChannels : 2,
      audioCodec : 'audio/mp4a-latm',
      audioSampleRate : 48000,
      fileFormat : 'mp4',
      videoBitrate : 48000,
      videoCodec : 'video/mp4v-es',
      videoFrameWidth : 640,
      videoFrameHeight : 480,
      videoFrameRate : 30
81
    }
W
wusongqing 已提交
82

83 84 85 86 87 88
    let videoConfig = {
      audioSourceType : 1,
      videoSourceType : 0,
      profile : videoProfile,
      url : this.testFdNumber, // testFdNumber由getFd生成
      orientationHint : 0,
89
      location : { latitude : 30, longitude : 130 }
90 91 92 93 94
    }
    // 创建videoRecorder对象
    await media.createVideoRecorder().then((recorder) => {
      console.info('case createVideoRecorder called');
      if (typeof (recorder) != 'undefined') {
W
wusongqing 已提交
95 96
        videoRecorder = recorder;
        console.info('createVideoRecorder success');
97
      } else {
W
wusongqing 已提交
98
        console.info('createVideoRecorder failed');
99 100 101 102 103 104 105 106 107 108 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
      }
    }, 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 已提交
149
```