1# 视频录制开发指导 2 3## 简介 4 5视频录制的主要工作是捕获音视频信号,完成音视频编码并保存到文件中,帮助开发者轻松实现音视频录制功能,包括开始录制、暂停录制、恢复录制、停止录制、释放资源等功能控制。它允许调用者指定录制的编码格式、封装格式、文件路径等参数。 6 7## 运作机制 8 9该模块提供了视频录制状态变化示意图和视频录制外部模块交互图。 10 11**图1** 视频录制状态变化示意图 12 13 14 15**图2** 视频录制外部模块交互图 16 17 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_LOCATION、ohos.permission.WRITE_MEDIA、ohos.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```