1# 录像(ArkTS) 2<!--Kit: Camera Kit--> 3<!--Subsystem: Multimedia--> 4<!--Owner: @qano--> 5<!--Designer: @leo_ysl--> 6<!--Tester: @xchaosioda--> 7<!--Adviser: @zengyawen--> 8 9在开发相机应用时,需要先[申请相关权限](camera-preparation.md)。 10 11相机应用可通过调用和控制相机设备,完成预览、拍照和录像等基础操作。 12 13录像也是相机应用的最重要功能之一,录像是循环帧的捕获。对于录像的流畅度,开发者可以参考[拍照](camera-shooting.md)中的步骤4,设置分辨率、闪光灯、焦距、照片质量及旋转角度等信息。 14 15## 开发步骤 16 17详细的API说明请参考[Camera API参考](../../reference/apis-camera-kit/arkts-apis-camera.md)。 18 191. 导入media模块。 20 21 创建录像输出流的SurfaceId以及录像输出的数据,都需要用到系统提供的[media接口](../../reference/apis-media-kit/arkts-apis-media.md)能力,导入media接口的方法如下。 22 23 ```ts 24 import { BusinessError } from '@kit.BasicServicesKit'; 25 import { camera } from '@kit.CameraKit'; 26 import { media } from '@kit.MediaKit'; 27 ``` 28 292. 创建Surface。 30 31 系统提供的media接口可以创建一个录像[AVRecorder](../../reference/apis-media-kit/arkts-apis-media-AVRecorder.md)实例,通过该实例的[getInputSurface](../../reference/apis-media-kit/arkts-apis-media-AVRecorder.md#getinputsurface9)方法获取SurfaceId,与录像输出流做关联,处理录像输出流输出的数据。 32 33 ```ts 34 async function getVideoSurfaceId(aVRecorderConfig: media.AVRecorderConfig): Promise<string | undefined> { // aVRecorderConfig可参考步骤3.创建录像输出流。 35 let avRecorder: media.AVRecorder | undefined = undefined; 36 try { 37 avRecorder = await media.createAVRecorder(); 38 } catch (error) { 39 let err = error as BusinessError; 40 console.error(`createAVRecorder call failed. error code: ${err.code}`); 41 } 42 if (avRecorder === undefined) { 43 return undefined; 44 } 45 await avRecorder.prepare(aVRecorderConfig, (err: BusinessError) => { 46 if (err == null) { 47 console.info('prepare success'); 48 } else { 49 console.error('prepare failed and error is ' + err.message); 50 } 51 }); 52 let videoSurfaceId = await avRecorder.getInputSurface(); 53 return videoSurfaceId; 54 } 55 ``` 56 573. 创建录像输出流。 58 59 通过[CameraOutputCapability](../../reference/apis-camera-kit/arkts-apis-camera-i.md#cameraoutputcapability)中的videoProfiles属性,可获取当前设备支持的录像输出流。然后,定义创建录像的参数,通过[createVideoOutput](../../reference/apis-camera-kit/arkts-apis-camera-CameraManager.md#createvideooutput)方法创建录像输出流。 60 61 > **说明:** 62 > 63 > 1.预览流与录像输出流的分辨率的宽高比要保持一致,如示例代码中宽高比为640:480 = 4:3,则需要预览流中的分辨率的宽高比也为4:3,如分辨率选择640:480,或960:720,或1440:1080,以此类推。 64 > 65 > 2.在设置预览输出流的分辨率宽高前,需要先通过[AVRecorderProfile](../../reference/apis-media-kit/arkts-apis-media-i.md#avrecorderprofile9)查询视频帧支持可配置的宽高范围。 66 > 67 > 3.获取录像旋转角度的方法:通过[VideoOutput](../../reference/apis-camera-kit/arkts-apis-camera-VideoOutput.md)中的[getVideoRotation](../../reference/apis-camera-kit/arkts-apis-camera-VideoOutput.md#getvideorotation12)方法获取rotation实际的值。 68 > 69 > 4.录像输出流帧率通过[CameraOutputCapability](../../reference/apis-camera-kit/arkts-apis-camera-i.md#cameraoutputcapability)中的videoProfiles属性,选择[VideoProfile](../../reference/apis-camera-kit/arkts-apis-camera-i.md#videoprofile)中[frameRateRange](../../reference/apis-camera-kit/arkts-apis-camera-i.md#frameraterange)满足实际业务需求的录像输出流videoProfile。 70 71 ```ts 72 async function getVideoOutput(cameraManager: camera.CameraManager, videoSurfaceId: string, cameraOutputCapability: camera.CameraOutputCapability): Promise<camera.VideoOutput | undefined> { 73 let videoProfilesArray: Array<camera.VideoProfile> = cameraOutputCapability.videoProfiles; 74 if (!videoProfilesArray) { 75 console.error("createOutput videoProfilesArray == null || undefined"); 76 return undefined; 77 } 78 // AVRecorderProfile。 79 let aVRecorderProfile: media.AVRecorderProfile = { 80 fileFormat : media.ContainerFormatType.CFT_MPEG_4, // 视频文件封装格式,只支持MP4。 81 videoBitrate : 100000, // 视频比特率。 82 videoCodec : media.CodecMimeType.VIDEO_AVC, // 视频文件编码格式,支持avc格式。 83 videoFrameWidth : 640, // 视频分辨率的宽。 84 videoFrameHeight : 480, // 视频分辨率的高。 85 videoFrameRate : 30 // 视频帧率。 86 }; 87 // 创建视频录制的参数,预览流与录像输出流的分辨率的宽(videoFrameWidth)高(videoFrameHeight)比要保持一致。 88 let avMetadata: media.AVMetadata = { 89 videoOrientation: '90' // rotation的值90,是通过getPhotoRotation接口获取到的值,具体请参考说明中获取录像旋转角度的方法。 90 } 91 92 let aVRecorderConfig: media.AVRecorderConfig = { 93 videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, 94 profile: aVRecorderProfile, 95 url: 'fd://35', // 此处为样例示范,需要根据开发需求填写实际的路径。 96 metadata: avMetadata 97 }; 98 // 创建avRecorder。 99 let avRecorder: media.AVRecorder | undefined = undefined; 100 try { 101 avRecorder = await media.createAVRecorder(); 102 } catch (error) { 103 let err = error as BusinessError; 104 console.error(`createAVRecorder call failed. error code: ${err.code}`); 105 } 106 if (avRecorder === undefined) { 107 return undefined; 108 } 109 // 设置视频录制的参数。 110 await avRecorder.prepare(aVRecorderConfig); 111 // 创建VideoOutput对象。 112 let videoOutput: camera.VideoOutput | undefined = undefined; 113 // createVideoOutput传入的videoProfile对象的宽高需要和aVRecorderProfile保持一致。 114 let videoProfile: undefined | camera.VideoProfile = videoProfilesArray.find((profile: camera.VideoProfile) => { 115 return profile.size.width === aVRecorderProfile.videoFrameWidth && profile.size.height === aVRecorderProfile.videoFrameHeight; 116 }); 117 if (!videoProfile) { 118 console.error('videoProfile is not found'); 119 return; 120 } 121 try { 122 videoOutput = cameraManager.createVideoOutput(videoProfile, videoSurfaceId); 123 } catch (error) { 124 let err = error as BusinessError; 125 console.error('Failed to create the videoOutput instance. errorCode = ' + err.code); 126 } 127 return videoOutput; 128 } 129 ``` 130 1314. 开始录像。 132 133 先通过videoOutput的[start](../../reference/apis-camera-kit/arkts-apis-camera-VideoOutput.md#start-1)方法启动录像输出流,再通过avRecorder的[start](../../reference/apis-media-kit/arkts-apis-media-AVRecorder.md#start9)方法开始录像。 134 135 ```ts 136 async function startVideo(videoOutput: camera.VideoOutput, avRecorder: media.AVRecorder): Promise<void> { 137 try { 138 await videoOutput.start(); 139 } catch (error) { 140 let err = error as BusinessError; 141 console.error(`start videoOutput failed, error: ${err.code}`); 142 } 143 avRecorder.start(async (err: BusinessError) => { 144 if (err) { 145 console.error(`Failed to start the video output ${err.message}`); 146 return; 147 } 148 console.info('Callback invoked to indicate the video output start success.'); 149 }); 150 } 151 ``` 152 1535. 停止录像。 154 155 先通过avRecorder的[stop](../../reference/apis-media-kit/arkts-apis-media-AVRecorder.md#stop9-1)方法停止录像,再通过videoOutput的[stop](../../reference/apis-camera-kit/arkts-apis-camera-VideoOutput.md#stop-1)方法停止录像输出流。 156 157 ```ts 158 async function stopVideo(videoOutput: camera.VideoOutput, avRecorder: media.AVRecorder): Promise<void> { 159 avRecorder.stop((err: BusinessError) => { 160 if (err) { 161 console.error(`Failed to stop the video output ${err.message}`); 162 return; 163 } 164 console.info('Callback invoked to indicate the video output stop success.'); 165 }); 166 await videoOutput.stop(); 167 } 168 ``` 169 170 171## 状态监听 172 173在相机应用开发过程中,可以随时监听录像输出流状态,包括录像开始、录像结束、录像流输出的错误。 174 175- 通过注册固定的frameStart回调函数获取监听录像开始结果,videoOutput创建成功时即可监听,录像第一次曝光时触发,有该事件返回结果则认为录像开始。 176 177 ```ts 178 function onVideoOutputFrameStart(videoOutput: camera.VideoOutput): void { 179 videoOutput.on('frameStart', (err: BusinessError) => { 180 if (err !== undefined && err.code !== 0) { 181 return; 182 } 183 console.info('Video frame started'); 184 }); 185 } 186 ``` 187 188- 通过注册固定的frameEnd回调函数获取监听录像结束结果,videoOutput创建成功时即可监听,录像完成最后一帧时触发,有该事件返回结果则认为录像流已结束。 189 190 ```ts 191 function onVideoOutputFrameEnd(videoOutput: camera.VideoOutput): void { 192 videoOutput.on('frameEnd', (err: BusinessError) => { 193 if (err !== undefined && err.code !== 0) { 194 return; 195 } 196 console.info('Video frame ended'); 197 }); 198 } 199 ``` 200 201- 通过注册固定的error回调函数获取监听录像输出错误结果,callback返回预览输出接口使用错误时对应的错误码,错误码类型参见[Camera错误码](../../reference/apis-camera-kit/arkts-apis-camera-e.md#cameraerrorcode)。 202 203 ```ts 204 function onVideoOutputError(videoOutput: camera.VideoOutput): void { 205 videoOutput.on('error', (error: BusinessError) => { 206 console.error(`Video output error code: ${error.code}`); 207 }); 208 } 209 ``` 210 211<!--RP1--> 212<!--RP1End-->