1/* 2 * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import media from '@ohos.multimedia.media'; 17import type resourceManager from '@ohos.resourceManager'; 18import emitter from '@ohos.events.emitter'; 19import Logger from '../utils/Logger'; 20 21const CASE_ZERO = 0; 22const CASE_ONE = 1; 23const CASE_TWO = 2; 24const CASE_THREE = 3; 25 26export default class AvPlayManage { 27 private tag: string = 'AVPlayManage'; 28 private flag: boolean; 29 private avPlayer: media.AVPlayer; 30 private surfaceID: string; 31 private mgr: resourceManager.ResourceManager; 32 private currentTime: number; // 视频当前时间 33 private durationTime: number; // 视频总长 34 private speedSelect: number; // 倍速选择 35 private fileDescriptor: resourceManager.RawFileDescriptor; 36 private videoSrc: string; 37 private fileSrc: string; 38 /** 39 * 初始化视频 40 */ 41 async initPlayer(surfaceId: string, callback: (avPlayer: media.AVPlayer) => void): Promise<void> { 42 Logger.info(this.tag, 'initPlayer==initCamera surfaceId== ${surfaceId}'); 43 this.surfaceID = surfaceId; 44 Logger.info(this.tag, 'initPlayer==this.surfaceID surfaceId== ${this.surfaceID}'); 45 try { 46 Logger.info(this.tag, 'initPlayer videoPlay avPlayerDemo'); 47 // 创建avPlayer实例对象 48 this.avPlayer = await media.createAVPlayer(); 49 // 创建状态机变化回调函数 50 await this.setAVPlayerCallback(callback); 51 Logger.info(this.tag, 'initPlayer videoPlay setAVPlayerCallback'); 52 this.mgr = globalThis.context.resourceManager; 53 Logger.info(this.tag, 'initPlayer videoPlay this.mgr'); 54 this.fileDescriptor = await this.mgr.getRawFd('test1.mp4'); 55 Logger.info(this.tag, 'initPlayer videoPlay fileDescriptor = ${JSON.stringify(this.fileDescriptor)}'); 56 this.avPlayer.fdSrc = this.fileDescriptor; 57 } catch (e) { 58 Logger.error(this.tag, 'initPlayer initPlayer err:${e}'); 59 } 60 } 61 62 // 注册avplayer回调函数 63 async setAVPlayerCallback(callback: (avPlayer: media.AVPlayer) => void, videoSrc?: string): Promise<void> { 64 // seek操作结果回调函数 65 this.avPlayer.on('seekDone', (seekDoneTime) => { 66 Logger.info(this.tag, 'setAVPlayerCallback AVPlayer seek succeeded, seek time is ${seekDoneTime}'); 67 }); 68 // error回调监听函数,当avPlayer在操作过程中出现错误时调用reset接口触发重置流程 69 this.avPlayer.on('error', (err) => { 70 Logger.error(this.tag, 'setAVPlayerCallback Invoke avPlayer failed, code is ${err.code}, message is ${err.message}'); 71 this.avPlayer.reset(); 72 }); 73 // 状态机变化回调函数 74 this.avPlayer.on('stateChange', async (state, reason) => { 75 switch (state) { 76 case 'idle': // 成功调用reset接口后触发该状态机上报 77 this.avPlayer.release(); 78 this.avPlayerChoose(callback); 79 Logger.info(this.tag, 'setAVPlayerCallback AVPlayer state idle called.'); 80 break; 81 case 'initialized': // avplayer 设置播放源后触发该状态上报 82 Logger.info(this.tag, 'setAVPlayerCallback AVPlayerstate initialized called.'); 83 this.avPlayer.surfaceId = this.surfaceID; // 设置显示画面,当播放的资源为纯音频时无需设置 84 Logger.info(this.tag, 'setAVPlayerCallback this.avPlayer.surfaceId = ${this.avPlayer.surfaceId}'); 85 this.avPlayer.prepare(); 86 break; 87 case 'prepared': // prepare调用成功后上报该状态机 88 Logger.info(this.tag, 'setAVPlayerCallback AVPlayer state prepared called.'); 89 this.durationTime = this.avPlayer.duration; 90 this.currentTime = this.avPlayer.currentTime; 91 this.avPlayer.play(); // 调用播放接口开始播放 92 Logger.info(this.tag, 'setAVPlayerCallback this.speedSelect = ${this.speedSelect}'); 93 switch (this.speedSelect) { 94 case CASE_ZERO: 95 this.videoSpeedOne(); 96 break; 97 case CASE_ONE: 98 this.videoSpeedOnePointTwentyFive(); 99 break; 100 case CASE_TWO: 101 this.videoSpeedOnePointSeventyFive(); 102 break; 103 case CASE_THREE: 104 this.videoSpeedTwo(); 105 break; 106 } 107 callback(this.avPlayer); 108 break; 109 case 'playing': // play成功调用后触发该状态机上报 110 Logger.info(this.tag, 'setAVPlayerCallback AVPlayer state playing called.'); 111 let eventDataTrue = { 112 data: { 113 'flag': true 114 } 115 }; 116 let innerEventTrue = { 117 eventId: 2, 118 priority: emitter.EventPriority.HIGH 119 }; 120 emitter.emit(innerEventTrue, eventDataTrue); 121 break; 122 case 'completed': // 播放结束后触发该状态机上报 123 Logger.info(this.tag, 'setAVPlayerCallback AVPlayer state completed called.'); 124 let eventDataFalse = { 125 data: { 126 'flag': false 127 } 128 }; 129 let innerEvent = { 130 eventId: 1, 131 priority: emitter.EventPriority.HIGH 132 }; 133 emitter.emit(innerEvent, eventDataFalse); 134 break; 135 default: 136 Logger.info(this.tag, 'setAVPlayerCallback AVPlayer state unknown called.'); 137 break; 138 } 139 }); 140 // 时间上报监听函数 141 this.avPlayer.on('timeUpdate', (time: number) => { 142 this.currentTime = time; 143 Logger.info(this.tag, 'setAVPlayerCallback timeUpdate success,and new time is = ${this.currentTime}'); 144 }); 145 } 146 147 /** 148 * 获取总时间 149 */ 150 getDurationTime(): number { 151 return this.durationTime; 152 } 153 154 /** 155 * 获取当前时间 156 */ 157 getCurrentTime(): number { 158 return this.currentTime; 159 } 160 161 /** 162 * 视频播放 163 */ 164 videoPlay(): void { 165 if (this.avPlayer) { 166 try { 167 this.avPlayer.play(); 168 } catch (e) { 169 Logger.error(this.tag, 'videoPlay = ${JSON.stringify(e)}'); 170 } 171 } 172 } 173 174 /** 175 * 视频暂停 176 */ 177 videoPause(): void { 178 if (this.avPlayer) { 179 try { 180 this.avPlayer.pause(); 181 Logger.info(this.tag, 'videoPause=='); 182 } catch (e) { 183 Logger.info(this.tag, 'videoPause== ${JSON.stringify(e)}'); 184 } 185 } 186 } 187 188 /** 189 * 调节1.0倍速 190 */ 191 videoSpeedOne(): void { 192 if (this.avPlayer) { 193 try { 194 this.avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X); 195 Logger.info(this.tag, 'videoSpeed_1_00'); 196 } catch (e) { 197 Logger.info(this.tag, 'videoSpeed_1_00== ${JSON.stringify(e)}'); 198 } 199 } 200 } 201 202 /** 203 * 调节1.25倍速 204 */ 205 videoSpeedOnePointTwentyFive(): void { 206 if (this.avPlayer) { 207 try { 208 this.avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_25_X); 209 Logger.info(this.tag, 'videoSpeed_1_25'); 210 } catch (e) { 211 Logger.info(this.tag, 'videoSpeed_1_25== ${JSON.stringify(e)}'); 212 } 213 } 214 } 215 216 /** 217 * 调节1.75倍速 218 */ 219 videoSpeedOnePointSeventyFive(): void { 220 if (this.avPlayer) { 221 try { 222 this.avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_75_X); 223 Logger.info(this.tag, 'videoSpeed_1_75'); 224 } catch (e) { 225 Logger.info(this.tag, 'videoSpeed_1_75==' + JSON.stringify(e)); 226 } 227 } 228 } 229 230 /** 231 * 调节2.0倍速 232 */ 233 videoSpeedTwo(): void { 234 if (this.avPlayer) { 235 try { 236 this.avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X); 237 Logger.info(this.tag, 'videoSpeed_2_0'); 238 } catch (e) { 239 Logger.info(this.tag, 'videoSpeed_2_0== ${JSON.stringify(e)}'); 240 } 241 } 242 } 243 244 /** 245 * 视频跳转 246 */ 247 videoSeek(seekTime: number): void { 248 if (this.avPlayer) { 249 try { 250 this.avPlayer.seek(seekTime, media.SeekMode.SEEK_PREV_SYNC); 251 Logger.info(this.tag, 'videoSeek== ${seekTime}'); 252 } catch (e) { 253 Logger.info(this.tag, 'videoSeek== ${JSON.stringify(e)}'); 254 } 255 } 256 } 257 258 /** 259 * 视频重置 260 */ 261 async videoReset(): Promise<void> { 262 this.avPlayer.reset(); 263 } 264 265 /** 266 * 释放视频资源 267 */ 268 async videoRelease(): Promise<void> { 269 this.avPlayer.release((err) => { 270 if (err == null) { 271 Logger.info(this.tag, 'videoRelease release success'); 272 } else { 273 Logger.error(this.tag, 'videoRelease release filed,error message is = ${err.message}'); 274 } 275 }); 276 } 277 278 /** 279 * 视频切换,前台调用 280 */ 281 async videoChoose(videoSrc: string, speedSelect: number, callback: (avPlayer: media.AVPlayer) => void): Promise<void> { 282 try { 283 this.flag = false; 284 this.videoSrc = videoSrc; 285 this.speedSelect = speedSelect; 286 Logger.info(this.tag, 'videoChoose this.videoSrc = ${this.videoSrc}'); 287 this.videoReset(); 288 } catch (e) { 289 Logger.info(this.tag, 'videoChoose== ${JSON.stringify(e)}'); 290 } 291 } 292 293 /** 294 * 视频切换,换视频资源 295 */ 296 async avPlayerChoose(callback: (avPlayer: media.AVPlayer) => void): Promise<void> { 297 try { 298 Logger.info(this.tag, 'avPlayerChoose avPlayerDemo'); 299 // 创建avPlayer实例对象 300 this.avPlayer = await media.createAVPlayer(); 301 // 创建状态机变化回调函数 302 this.fileDescriptor = null; 303 Logger.info(this.tag, 'avPlayerChoose this.fileDescriptor = ${this.fileDescriptor}'); 304 await this.setAVPlayerCallback(callback); 305 Logger.info(this.tag, 'avPlayerChoose setAVPlayerCallback'); 306 if (this.videoSrc === 'network.mp4') { 307 this.fileSrc = 'https:\/\/vd3.bdstatic.com\/mda-pdc2kmwtd2vxhiy4\/cae_h264\/1681502407203843413\/mda-pdc2kmwtd2vxhiy4.mp4'; 308 } else { 309 this.fileSrc = this.videoSrc; 310 } 311 let regex = /^(http|https)/i; 312 let bool = regex.test(this.fileSrc); 313 if (bool) { 314 Logger.info(this.tag, 'avPlayerChoose avPlayerChoose fileDescriptor = ${JSON.stringify(this.fileDescriptor)}'); 315 this.avPlayer.url = this.fileSrc; 316 } else { 317 this.fileDescriptor = await this.mgr.getRawFd(this.fileSrc); 318 Logger.info(this.tag, 'avPlayerChoose avPlayerChoose fileDescriptor = ${JSON.stringify(this.fileDescriptor)}'); 319 this.avPlayer.fdSrc = this.fileDescriptor; 320 } 321 } catch (e) { 322 Logger.info(this.tag, 'avPlayerChoose trycatch avPlayerChoose'); 323 this.videoReset(); 324 } 325 } 326}