xugenyuan

ref |> 新增阿里播放器SDK封装

因为依赖license
目前未开启

Signed-off-by: xugenyuan <xugenyuan@wondertek.com.cn>
@@ -11,3 +11,7 @@ export { PlayerConstants } from "./src/main/ets/constants/PlayerConstants" @@ -11,3 +11,7 @@ export { PlayerConstants } from "./src/main/ets/constants/PlayerConstants"
11 export { SpeedBean } from "./src/main/ets/bean/SpeedBean" 11 export { SpeedBean } from "./src/main/ets/bean/SpeedBean"
12 12
13 export { DateFormatUtil } from "./src/main/ets/utils/DateFormatUtil" 13 export { DateFormatUtil } from "./src/main/ets/utils/DateFormatUtil"
  14 +
  15 +export { WDAliPlayerController } from "./src/main/ets/controller/WDAliPlayerController"
  16 +
  17 +export { WDListPlayerData, WDAliListPlayerController } from "./src/main/ets/controller/WDAliListPlayerController"
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 "main": "Index.ets", 7 "main": "Index.ets",
8 "version": "1.0.0", 8 "version": "1.0.0",
9 "dependencies": { 9 "dependencies": {
10 - "wdKit": "file:../../commons/wdKit" 10 + "wdKit": "file:../../commons/wdKit",
  11 + "premierlibrary": "file:./libs/premierlibrary.har"
11 } 12 }
12 } 13 }
@@ -5,6 +5,8 @@ export class PlayerConstants { @@ -5,6 +5,8 @@ export class PlayerConstants {
5 static readonly STATUS_START: number = 1; 5 static readonly STATUS_START: number = 1;
6 static readonly STATUS_PAUSE: number = 2; 6 static readonly STATUS_PAUSE: number = 2;
7 static readonly STATUS_STOP: number = 3; 7 static readonly STATUS_STOP: number = 3;
  8 + static readonly STATUS_ERROR: number = 4;
  9 + static readonly STATUS_COMPLETION: number = 5;
8 10
9 static readonly OPERATE_STATE: Array<string> = ['prepared','playing', 'paused', 'completed']; 11 static readonly OPERATE_STATE: Array<string> = ['prepared','playing', 'paused', 'completed'];
10 12
  1 +import { AliPlayerFactory, AliPlayer, InfoBean, UrlSource, ErrorInfo, InfoCode } from 'premierlibrary';
  2 +import {
  3 + idle,
  4 + initalized,
  5 + prepared,
  6 + started,
  7 + paused,
  8 + stopped,
  9 + completion,
  10 + error} from 'premierlibrary/src/main/ets/com/aliyun/player/IPlayer';
  11 +import { AliListPlayer } from 'premierlibrary/src/main/ets/com/aliyun/player/AliListPlayer'
  12 +
  13 +import { initGlobalPlayerSettings, setupPlayerConfig } from '../utils/GlobalSetting';
  14 +import prompt from '@ohos.promptAction';
  15 +import { Logger } from '../utils/Logger';
  16 +import { PlayerConstants, AVPlayerStatus, Events } from '../constants/PlayerConstants';
  17 +
  18 +export interface WDListPlayerData {
  19 + uid: string
  20 + url: string
  21 + surfaceId?: string
  22 +}
  23 +
  24 +/*
  25 +
  26 + * 此播放器为阿里播放器鸿蒙版本封装,可播放单个视频、列表多个视频
  27 + * 列表上下滑场景用:WDAliListPlayerController
  28 + *
  29 + * 阿里文档链接:https://help.aliyun.com/zh/apsara-video-sdk/developer-reference/integrated-hongmeng-harmonyos-next-framework-player-sdk
  30 + */
  31 +@Observed
  32 +export class WDAliListPlayerController {
  33 + private initPromise: Promise<void>;
  34 + private avPlayer?: AliListPlayer;
  35 +
  36 + // 内部播放器状态
  37 + private avPlayerStatus: number = idle
  38 + private duration: number = 0;
  39 + private status: number = PlayerConstants.STATUS_IDLE;
  40 + private loop: boolean = false;
  41 + private url: string = '';
  42 + private surfaceId: string = '';
  43 + private playSpeed: number = 1;
  44 + private seekTime: number = 0;
  45 + private positionY: number = 0;
  46 + private startTime: number = 0
  47 +
  48 + public errorCode?: number
  49 + public errorMesage?: string
  50 +
  51 + public onVideoSizeChange?: (width: number, height: number) => void;
  52 + public onBufferUpdate?: (buffered: number, duration: number) => void;
  53 + public onTimeUpdate?: (position: number, duration: number) => void;
  54 + public onVolumeUpdate?: (volume: number) => void;
  55 +
  56 + // 播放完成,决定是否继续播放回调
  57 + public continue?: () => void;
  58 +
  59 + // 准备完成,决定是否播放回调。如果不实现,则自动播放
  60 + public onCanplay?: () => void;
  61 + public onStatusChange?: (status: number) => void;
  62 + public onFirstFrameDisplay?: () => void
  63 +
  64 + //// ------------ 以下为列表播放器属性
  65 + private playSources: WDListPlayerData[] = []
  66 + private currentPlayRecord?: WDListPlayerData
  67 +
  68 + constructor() {
  69 + Logger.info("初始化")
  70 + initGlobalPlayerSettings()
  71 + this.initPromise = this.createAVPlayer();
  72 + }
  73 +
  74 + /**
  75 + * 创建 videoPlayer对象
  76 + */
  77 + private createAVPlayer(): Promise<void> {
  78 + return new Promise((resolve, reject) => {
  79 + Logger.debug("开始创建")
  80 + let traceId = ''
  81 + this.avPlayer = AliPlayerFactory.createAliListPlayer(getContext(), traceId)
  82 + if (this.avPlayer) {
  83 + Logger.debug("创建完成1")
  84 + setupPlayerConfig(this.avPlayer!)
  85 + this.bindState();
  86 + resolve();
  87 + } else {
  88 + Logger.error("创建完成0")
  89 + Logger.error('[WDPlayerController] createAvPlayer fail!');
  90 + reject();
  91 + }
  92 + });
  93 + }
  94 +
  95 + public destory() {
  96 + Logger.debug("播放器销毁")
  97 + this.avPlayer?.stop()
  98 + this.avPlayer?.release()
  99 + this.playSources = []
  100 + this.currentPlayRecord = undefined
  101 + }
  102 +
  103 + /**
  104 + * AliPlayer 绑定事件.
  105 + */
  106 + private bindState() {
  107 + this.avPlayer?.setOnPreparedListener({
  108 + // 当调用play()方法后,会调用
  109 + onPrepared: () => {
  110 + this.duration = this.avPlayer?.getDuration();
  111 + Logger.debug("已准备好", `${this.duration}`)
  112 + }
  113 + }
  114 + );
  115 + this.avPlayer?.setOnRenderingStartListener({
  116 + onRenderingStart: () => {
  117 + Logger.debug("首帧开始显示")
  118 + if (this.onFirstFrameDisplay) {
  119 + this.onFirstFrameDisplay()
  120 + }
  121 + }
  122 + });
  123 + this.avPlayer?.setOnCompletionListener({
  124 + onCompletion: () => {
  125 + Logger.debug("播放完成")
  126 + }
  127 + });
  128 + this.avPlayer?.setOnInfoListener({
  129 + onInfo: (bean: InfoBean) => {
  130 +
  131 + if (bean.getCode() === InfoCode.CurrentPosition) {
  132 + let position : number = bean.getExtraValue()
  133 + Logger.debug(`播放进度条:${position}/ ${this.duration}`)
  134 + this.initProgress(position);
  135 +
  136 + } else if (bean.getCode() === InfoCode.BufferedPosition) {
  137 + let buffer : number = bean.getExtraValue()
  138 + if (this.onBufferUpdate) {
  139 + this.onBufferUpdate(buffer, this.duration)
  140 + }
  141 +
  142 + } else if (bean.getCode() === InfoCode.SwitchToSoftwareVideoDecoder) {
  143 + Logger.debug(`DOWNGRADE TO SOFTWARE DECODE`)
  144 + // this.mSwitchedToSoftListener?.onSwitched();
  145 + }
  146 + }
  147 + });
  148 + this.avPlayer?.setOnStateChangedListener({
  149 + onStateChanged: (status: number) => {
  150 + this.avPlayerStatus = status
  151 + Logger.debug("status update:" + `${this.getStatusStringWith(status)}`)
  152 +
  153 + switch (status) {
  154 + case initalized: {
  155 + //this.avPlayer?.prepare();
  156 + } break
  157 + case prepared: {
  158 + if (this.startTime) {
  159 + this.setSeekTime(this.startTime, SliderChangeMode.Begin);
  160 + }
  161 + this.duration = this.avPlayer?.getDuration();
  162 + if (this.onVideoSizeChange) {
  163 + this.onVideoSizeChange(this.avPlayer?.getVideoWidth(), this.avPlayer?.getVideoHeight());
  164 + }
  165 + if (this.onCanplay) {
  166 + this.onCanplay()
  167 + } else {
  168 + this.play()
  169 + }
  170 + } break
  171 + case started: {
  172 + this.setBright();
  173 + this.status = PlayerConstants.STATUS_START;
  174 + this.watchStatus();
  175 + } break
  176 + case paused: {
  177 + this.status = PlayerConstants.STATUS_PAUSE;
  178 + this.watchStatus();
  179 + } break
  180 + case stopped: {
  181 + this.status = PlayerConstants.STATUS_STOP;
  182 + this.watchStatus();
  183 + } break
  184 + case completion: {
  185 + this.status = PlayerConstants.STATUS_COMPLETION;
  186 + this.watchStatus();
  187 + if (this.continue) {
  188 + this.continue();
  189 + } else {
  190 + //TODO:
  191 + //this.duration = 0;
  192 + //this.url = this.avPlayer.url || '';
  193 + //this.avPlayer.reset();
  194 + }
  195 + } break
  196 + case error: {
  197 + // 这里拿不到错误信息
  198 + // this.status = PlayerConstants.STATUS_ERROR;
  199 + // this.watchStatus();
  200 + }
  201 + }
  202 + }
  203 + });
  204 + this.avPlayer?.setOnErrorListener({
  205 + onError:(errorInfo) => {
  206 + Logger.error("播放错误", JSON.stringify(errorInfo))
  207 + this.errorCode = errorInfo.getCode()
  208 + this.errorMesage = errorInfo.getMsg()
  209 + this.status = PlayerConstants.STATUS_ERROR;
  210 + this.watchStatus();
  211 + }
  212 + });
  213 + this.avPlayer?.setOnLoadingStatusListener({
  214 + onLoadingBegin: () => {
  215 + // Logger.error("开始加载。。。")
  216 + },
  217 + onLoadingProgress: (percent: number, netSpeed: number) => {
  218 + // this.loadingProgress = percent;
  219 + // this.loadingSpeed = netSpeed;
  220 + },
  221 + onLoadingEnd: () => {
  222 + // Logger.error("结束加载")
  223 + // this.showLoadingScene = false;
  224 + // this.loadingProgress = 0;
  225 + // this.loadingSpeed = 0;
  226 + }
  227 + });
  228 + this.avPlayer?.setOnSeekCompleteListener({
  229 + onSeekComplete: () => {
  230 + this.initProgress(this.avPlayer?.getCurrentPosition());
  231 + }
  232 + })
  233 + }
  234 +
  235 + private getStatusStringWith(status: number) : string {
  236 + switch (status) {
  237 + case idle: return 'idle'
  238 + case initalized: return 'initalized'
  239 + case prepared: return 'prepared'
  240 + case started: return 'started'
  241 + case paused: return 'paused'
  242 + case stopped: return 'stopped'
  243 + case completion: return 'completion'
  244 + case error: return 'error'
  245 + }
  246 + return 'unknow'
  247 + }
  248 +
  249 + public setXComponentController(controller: XComponentController) {
  250 + this.setSurfaceId(controller.getXComponentSurfaceId())
  251 + }
  252 +
  253 + public setSurfaceId(surfaceId: string) {
  254 + this.surfaceId = surfaceId
  255 + }
  256 +
  257 + public async addSources(sources: WDListPlayerData[]) {
  258 + if (this.avPlayer == null) {
  259 + Logger.info("等待播放器初始化")
  260 + await this.initPromise;
  261 + }
  262 + if (this.avPlayer == null) {
  263 + return
  264 + }
  265 +
  266 + /// 追加数据源
  267 + this.playSources.splice(this.playSources.length, 0, ...sources)
  268 + sources.map(data => {
  269 + this.avPlayer?.addUrl(data.url, data.uid)
  270 + })
  271 + }
  272 +
  273 + public moveTo(uid: string, surfaceId: string) {
  274 + let uidDatas = this.playSources.filter(data => data.uid === uid)
  275 + if (uidDatas.length == 0) {
  276 + Logger.info("请先addSources()添加数据源url" + uid)
  277 + return
  278 + }
  279 + this.currentPlayRecord = uidDatas[0]
  280 + this.avPlayer?.setSurfaceId(surfaceId)
  281 +
  282 + // this.setAliPlayerURL(this.currentPlayRecord.url)
  283 +
  284 + let result = this.avPlayer?.moveTo(uid)
  285 + Logger.info("moveTo" + uid + ` result:${result}`)
  286 + this.avPlayer?.prepare()
  287 + }
  288 +
  289 + private setAliPlayerURL(url: string) {
  290 + let urlSource : UrlSource = new UrlSource()
  291 + urlSource.setUri(url)
  292 + this.avPlayer?.setUrlDataSource(urlSource)
  293 + }
  294 +
  295 + private release() {
  296 + if (this.avPlayer == null) {
  297 + return
  298 + }
  299 + this.avPlayer.release()
  300 + this.avPlayer = undefined
  301 + }
  302 +
  303 + public pause() {
  304 + Logger.debug("暂停", this.url)
  305 + this.avPlayer?.pause();
  306 + }
  307 +
  308 + public play() {
  309 + Logger.debug("播放", this.url)
  310 + this.avPlayer?.start();
  311 + }
  312 +
  313 + public stop() {
  314 + Logger.debug("停止", this.url)
  315 + this.avPlayer?.stop();
  316 + }
  317 +
  318 + public setLoop(loop: boolean) {
  319 + this.loop = loop;
  320 + this.avPlayer?.setLoop(loop);
  321 + }
  322 +
  323 + public setMute(mute: boolean) {
  324 + this.avPlayer?.setMute(mute)
  325 + }
  326 +
  327 + public setSpeed(playSpeed: number) {
  328 + this.playSpeed = playSpeed;
  329 + this.avPlayer?.setSpeed(this.playSpeed);
  330 + }
  331 +
  332 + public switchPlayOrPause() {
  333 + if (this.avPlayerStatus == started) {
  334 + this.avPlayer?.pause();
  335 + } else if (this.avPlayerStatus == completion) {
  336 + this.avPlayer?.seekTo(0, 0)
  337 + this.avPlayer?.start()
  338 + } else {
  339 + this.avPlayer?.start();
  340 + }
  341 + }
  342 +
  343 + public setSeekTime(value: number, mode: SliderChangeMode) {
  344 + // if (this.avPlayer == null) {
  345 + // await this.initPromise;
  346 + // }
  347 + // if (this.avPlayer == null) {
  348 + // return
  349 + // }
  350 + // if (mode == SliderChangeMode.Begin) {
  351 + // this.seekTime = value * 1000;
  352 + // this.avPlayer?.seek(this.seekTime, media.SeekMode.SEEK_PREV_SYNC);
  353 + // }
  354 + if (mode === SliderChangeMode.Moving) {
  355 + // this.progressThis.progressVal = value;
  356 + // this.progressThis.currentTime = DateFormatUtil.secondToTime(Math.floor(value * this.duration /
  357 + // 100 / 1000));
  358 + }
  359 + if (mode === SliderChangeMode.End) {
  360 + this.seekTime = Math.floor(value * this.duration / 100);
  361 + this.avPlayer?.seekTo(this.seekTime, 0);
  362 + }
  363 + }
  364 +
  365 + public setBright() {
  366 + // globalThis.windowClass.setWindowBrightness(this.playerThis.bright)
  367 + }
  368 +
  369 + public getStatus() {
  370 + return this.status;
  371 + }
  372 +
  373 + public getPlayer() {
  374 + return this.avPlayer != undefined
  375 + }
  376 +
  377 + initProgress(time: number) {
  378 + if (this.onTimeUpdate) {
  379 + this.onTimeUpdate(time, this.duration);
  380 + }
  381 + }
  382 +
  383 + resetProgress() {
  384 + this.seekTime = 0;
  385 + this.duration = 0;
  386 + }
  387 +
  388 + onVolumeActionStart(event: GestureEvent) {
  389 + this.positionY = event.offsetY;
  390 + }
  391 +
  392 + onBrightActionStart(event: GestureEvent) {
  393 + this.positionY = event.offsetY;
  394 + }
  395 +
  396 + volume: number = 1
  397 +
  398 + onVolumeActionUpdate(event: GestureEvent) {
  399 + if (!this.avPlayer) {
  400 + return
  401 + }
  402 + if (this.avPlayerStatus != prepared &&
  403 + this.avPlayerStatus != started &&
  404 + this.avPlayerStatus != paused &&
  405 + this.avPlayerStatus != completion) {
  406 + return;
  407 + }
  408 + let changeVolume = (event.offsetY - this.positionY) / 300;
  409 + let currentVolume = this.volume - changeVolume;
  410 + if (currentVolume > 1) {
  411 + currentVolume = 1;
  412 + }
  413 + if (currentVolume <= 0) {
  414 + currentVolume = 0;
  415 + }
  416 + this.volume = currentVolume;
  417 + this.avPlayer?.setVolume(this.volume);
  418 + this.positionY = event.offsetY;
  419 + if (this.onVolumeUpdate) {
  420 + this.onVolumeUpdate(this.volume);
  421 + }
  422 + console.log("volume : " + this.volume)
  423 + }
  424 +
  425 + onBrightActionUpdate(event: GestureEvent) {
  426 + // if (!this.playerThis.volumeShow) {
  427 + // this.playerThis.brightShow = true;
  428 + // let changeBright = (this.positionY - event.offsetY) / globalThis.screenHeight;
  429 + // let currentBright = this.playerThis.bright + changeBright;
  430 + // let brightMinFlag = currentBright <= 0;
  431 + // let brightMaxFlag = currentBright > 1;
  432 + // this.playerThis.bright = brightMinFlag ? 0 :
  433 + // (brightMaxFlag ? 1 : currentBright);
  434 + // this.setBright();
  435 + // this.positionY = event.offsetY;
  436 + // }
  437 + }
  438 +
  439 + onActionEnd() {
  440 + setTimeout(() => {
  441 + this.positionY = 0;
  442 + }, 200);
  443 + }
  444 +
  445 + watchStatus() {
  446 + console.log('watchStatus', this.status)
  447 + if (this.onStatusChange) {
  448 + this.onStatusChange(this.status)
  449 + }
  450 + // if (this.status === PlayConstants.STATUS_START) {
  451 + // globalThis.windowClass.setWindowKeepScreenOn(true);
  452 + // } else {
  453 + // globalThis.windowClass.setWindowKeepScreenOn(false);
  454 + // }
  455 + }
  456 +
  457 + playError(msg?: string) {
  458 + prompt.showToast({
  459 + duration: 3000,
  460 + message: msg ? msg : "请检查地址输入正确且网络正常"
  461 + });
  462 + }
  463 +
  464 + setStartTime(time?: number) {
  465 + this.startTime = time ?? 0;
  466 + }
  467 +}
  1 +import { AliPlayerFactory, AliPlayer, InfoBean, UrlSource, ErrorInfo, InfoCode } from 'premierlibrary';
  2 +import {
  3 + idle,
  4 + initalized,
  5 + prepared,
  6 + started,
  7 + paused,
  8 + stopped,
  9 + completion,
  10 + error} from 'premierlibrary/src/main/ets/com/aliyun/player/IPlayer';
  11 +
  12 +import { initGlobalPlayerSettings, setupPlayerConfig } from '../utils/GlobalSetting';
  13 +import prompt from '@ohos.promptAction';
  14 +import { Logger } from '../utils/Logger';
  15 +import { PlayerConstants, AVPlayerStatus, Events } from '../constants/PlayerConstants';
  16 +
  17 +/*
  18 + * 此播放器为阿里播放器鸿蒙版本封装,可播放单个视频、或直播
  19 + * 列表上下滑场景用:WDListPlayerController
  20 + *
  21 + * 阿里文档链接:https://help.aliyun.com/zh/apsara-video-sdk/developer-reference/integrated-hongmeng-harmonyos-next-framework-player-sdk
  22 + */
  23 +@Observed
  24 +export class WDAliPlayerController {
  25 + private initPromise: Promise<void>;
  26 + private avPlayer?: AliPlayer;
  27 +
  28 + // 内部播放器状态
  29 + private avPlayerStatus: number = idle
  30 + private duration: number = 0;
  31 + private status: number = PlayerConstants.STATUS_IDLE;
  32 + private loop: boolean = false;
  33 + private url: string = '';
  34 + private surfaceId: string = '';
  35 + private playSpeed: number = 1;
  36 + private seekTime: number = 0;
  37 + private positionY: number = 0;
  38 + private startTime: number = 0
  39 +
  40 + public errorCode?: number
  41 + public errorMesage?: string
  42 +
  43 + public onVideoSizeChange?: (width: number, height: number) => void;
  44 + public onBufferUpdate?: (buffered: number, duration: number) => void;
  45 + public onTimeUpdate?: (position: number, duration: number) => void;
  46 + public onVolumeUpdate?: (volume: number) => void;
  47 +
  48 + // 播放完成,决定是否继续播放回调
  49 + public continue?: () => void;
  50 +
  51 + // 准备完成,决定是否播放回调。如果不实现,则自动播放
  52 + public onCanplay?: () => void;
  53 + public onStatusChange?: (status: number) => void;
  54 + public onFirstFrameDisplay?: () => void
  55 +
  56 + constructor() {
  57 + Logger.info("初始化")
  58 + initGlobalPlayerSettings()
  59 + this.initPromise = this.createAVPlayer();
  60 + }
  61 +
  62 + /**
  63 + * 创建 videoPlayer对象
  64 + */
  65 + private createAVPlayer(): Promise<void> {
  66 + return new Promise((resolve, reject) => {
  67 + Logger.debug("开始创建")
  68 + let traceId = ''
  69 + this.avPlayer = AliPlayerFactory.createAliPlayer(getContext(), traceId)
  70 + if (this.avPlayer) {
  71 + Logger.debug("创建完成1")
  72 + setupPlayerConfig(this.avPlayer!)
  73 + this.bindState();
  74 + resolve();
  75 + } else {
  76 + Logger.error("创建完成0")
  77 + Logger.error('[WDPlayerController] createAvPlayer fail!');
  78 + reject();
  79 + }
  80 + });
  81 + }
  82 +
  83 + public destory() {
  84 + Logger.debug("播放器销毁")
  85 + this.avPlayer?.stop()
  86 + this.avPlayer?.release()
  87 + }
  88 +
  89 + /**
  90 + * AliPlayer 绑定事件.
  91 + */
  92 + private bindState() {
  93 + this.avPlayer?.setOnPreparedListener({
  94 + // 当调用play()方法后,会调用
  95 + onPrepared: () => {
  96 + this.duration = this.avPlayer?.getDuration();
  97 + Logger.debug("已准备好", `${this.duration}`)
  98 + }
  99 + }
  100 + );
  101 + this.avPlayer?.setOnRenderingStartListener({
  102 + onRenderingStart: () => {
  103 + Logger.debug("首帧开始显示")
  104 + if (this.onFirstFrameDisplay) {
  105 + this.onFirstFrameDisplay()
  106 + }
  107 + }
  108 + });
  109 + this.avPlayer?.setOnCompletionListener({
  110 + onCompletion: () => {
  111 + Logger.debug("播放完成")
  112 + }
  113 + });
  114 + this.avPlayer?.setOnInfoListener({
  115 + onInfo: (bean: InfoBean) => {
  116 +
  117 + if (bean.getCode() === InfoCode.CurrentPosition) {
  118 + let position : number = bean.getExtraValue()
  119 + Logger.debug(`播放进度条:${position}/ ${this.duration}`)
  120 + this.initProgress(position);
  121 +
  122 + } else if (bean.getCode() === InfoCode.BufferedPosition) {
  123 + let buffer : number = bean.getExtraValue()
  124 + if (this.onBufferUpdate) {
  125 + this.onBufferUpdate(buffer, this.duration)
  126 + }
  127 +
  128 + } else if (bean.getCode() === InfoCode.SwitchToSoftwareVideoDecoder) {
  129 + Logger.debug(`DOWNGRADE TO SOFTWARE DECODE`)
  130 + // this.mSwitchedToSoftListener?.onSwitched();
  131 + }
  132 + }
  133 + });
  134 + this.avPlayer?.setOnStateChangedListener({
  135 + onStateChanged: (status: number) => {
  136 + this.avPlayerStatus = status
  137 + Logger.debug("status update:" + `${this.getStatusStringWith(status)}`)
  138 +
  139 + switch (status) {
  140 + case initalized: {
  141 + //this.avPlayer?.prepare();
  142 + } break
  143 + case prepared: {
  144 + if (this.startTime) {
  145 + this.setSeekTime(this.startTime, SliderChangeMode.Begin);
  146 + }
  147 + this.duration = this.avPlayer?.getDuration();
  148 + if (this.onVideoSizeChange) {
  149 + this.onVideoSizeChange(this.avPlayer?.getVideoWidth(), this.avPlayer?.getVideoHeight());
  150 + }
  151 + if (this.onCanplay) {
  152 + this.onCanplay()
  153 + } else {
  154 + this.play()
  155 + }
  156 + } break
  157 + case started: {
  158 + this.setBright();
  159 + this.status = PlayerConstants.STATUS_START;
  160 + this.watchStatus();
  161 + } break
  162 + case paused: {
  163 + this.status = PlayerConstants.STATUS_PAUSE;
  164 + this.watchStatus();
  165 + } break
  166 + case stopped: {
  167 + this.status = PlayerConstants.STATUS_STOP;
  168 + this.watchStatus();
  169 + } break
  170 + case completion: {
  171 + this.status = PlayerConstants.STATUS_COMPLETION;
  172 + this.watchStatus();
  173 + if (this.continue) {
  174 + this.continue();
  175 + } else {
  176 + //TODO:
  177 + //this.duration = 0;
  178 + //this.url = this.avPlayer.url || '';
  179 + //this.avPlayer.reset();
  180 + }
  181 + } break
  182 + case error: {
  183 + // 这里拿不到错误信息
  184 + // this.status = PlayerConstants.STATUS_ERROR;
  185 + // this.watchStatus();
  186 + }
  187 + }
  188 + }
  189 + });
  190 + this.avPlayer?.setOnErrorListener({
  191 + onError:(errorInfo) => {
  192 + Logger.error("播放错误", JSON.stringify(errorInfo))
  193 + this.errorCode = errorInfo.getCode()
  194 + this.errorMesage = errorInfo.getMsg()
  195 + this.status = PlayerConstants.STATUS_ERROR;
  196 + this.watchStatus();
  197 + }
  198 + });
  199 + this.avPlayer?.setOnLoadingStatusListener({
  200 + onLoadingBegin: () => {
  201 + // Logger.error("开始加载。。。")
  202 + },
  203 + onLoadingProgress: (percent: number, netSpeed: number) => {
  204 + // this.loadingProgress = percent;
  205 + // this.loadingSpeed = netSpeed;
  206 + },
  207 + onLoadingEnd: () => {
  208 + // Logger.error("结束加载")
  209 + // this.showLoadingScene = false;
  210 + // this.loadingProgress = 0;
  211 + // this.loadingSpeed = 0;
  212 + }
  213 + });
  214 + this.avPlayer?.setOnSeekCompleteListener({
  215 + onSeekComplete: () => {
  216 + this.initProgress(this.avPlayer?.getCurrentPosition());
  217 + }
  218 + })
  219 + }
  220 +
  221 + private setAliPlayerURL(url: string) {
  222 + let urlSource : UrlSource = new UrlSource()
  223 + urlSource.setUri(url)
  224 + this.avPlayer?.setUrlDataSource(urlSource)
  225 + }
  226 +
  227 + private getStatusStringWith(status: number) : string {
  228 + switch (status) {
  229 + case idle: return 'idle'
  230 + case initalized: return 'initalized'
  231 + case prepared: return 'prepared'
  232 + case started: return 'started'
  233 + case paused: return 'paused'
  234 + case stopped: return 'stopped'
  235 + case completion: return 'completion'
  236 + case error: return 'error'
  237 + }
  238 + return 'unknow'
  239 + }
  240 +
  241 + setXComponentController(controller: XComponentController) {
  242 + this.setSurfaceId(controller.getXComponentSurfaceId())
  243 + }
  244 +
  245 + setSurfaceId(surfaceId: string) {
  246 + this.surfaceId = surfaceId
  247 + }
  248 +
  249 + async firstPlay(url: string) {
  250 + this.url = url;
  251 + if (this.avPlayer == null) {
  252 + Logger.info("等待播放器初始化")
  253 + await this.initPromise;
  254 + } else {
  255 + if (this.avPlayerStatus != idle) {
  256 + this.destory()
  257 + this.initPromise = this.createAVPlayer();
  258 + await this.initPromise;
  259 + }
  260 + }
  261 + if (this.avPlayer == null) {
  262 + return
  263 + }
  264 + this.duration = 0
  265 + this.errorCode = undefined
  266 + this.errorMesage = undefined
  267 + this.avPlayerStatus = idle
  268 + this.status = PlayerConstants.STATUS_IDLE
  269 +
  270 + this.avPlayer?.setAutoPlay(false)
  271 +
  272 + Logger.debug("开始播放", this.url)
  273 + this.setAliPlayerURL(this.url);
  274 +
  275 + Logger.info("设置SurfaceId" + this.surfaceId)
  276 + this.avPlayer?.setSurfaceId(this.surfaceId)
  277 +
  278 + this.avPlayer?.prepare()
  279 + }
  280 +
  281 + release() {
  282 + if (this.avPlayer == null) {
  283 + return
  284 + }
  285 + this.avPlayer.release()
  286 + this.avPlayer = undefined
  287 + }
  288 +
  289 + pause() {
  290 + Logger.debug("暂停", this.url)
  291 + this.avPlayer?.pause();
  292 + }
  293 +
  294 + play() {
  295 + Logger.debug("播放", this.url)
  296 + this.avPlayer?.start();
  297 + }
  298 +
  299 + stop() {
  300 + Logger.debug("停止", this.url)
  301 + this.avPlayer?.stop();
  302 + }
  303 +
  304 + setLoop(loop: boolean) {
  305 + this.loop = loop;
  306 + this.avPlayer?.setLoop(loop);
  307 + }
  308 +
  309 + setMute(mute: boolean) {
  310 + this.avPlayer?.setMute(mute)
  311 + }
  312 +
  313 + setSpeed(playSpeed: number) {
  314 + this.playSpeed = playSpeed;
  315 + this.avPlayer?.setSpeed(this.playSpeed);
  316 + }
  317 +
  318 + switchPlayOrPause() {
  319 + if (this.avPlayerStatus == started) {
  320 + this.avPlayer?.pause();
  321 + } else if (this.avPlayerStatus == completion) {
  322 + this.avPlayer?.seekTo(0, 0)
  323 + this.avPlayer?.start()
  324 + } else {
  325 + this.avPlayer?.start();
  326 + }
  327 + }
  328 +
  329 + setSeekTime(value: number, mode: SliderChangeMode) {
  330 + // if (this.avPlayer == null) {
  331 + // await this.initPromise;
  332 + // }
  333 + // if (this.avPlayer == null) {
  334 + // return
  335 + // }
  336 + // if (mode == SliderChangeMode.Begin) {
  337 + // this.seekTime = value * 1000;
  338 + // this.avPlayer?.seek(this.seekTime, media.SeekMode.SEEK_PREV_SYNC);
  339 + // }
  340 + if (mode === SliderChangeMode.Moving) {
  341 + // this.progressThis.progressVal = value;
  342 + // this.progressThis.currentTime = DateFormatUtil.secondToTime(Math.floor(value * this.duration /
  343 + // 100 / 1000));
  344 + }
  345 + if (mode === SliderChangeMode.End) {
  346 + this.seekTime = Math.floor(value * this.duration / 100);
  347 + this.avPlayer?.seekTo(this.seekTime, 0);
  348 + }
  349 + }
  350 +
  351 + setBright() {
  352 + // globalThis.windowClass.setWindowBrightness(this.playerThis.bright)
  353 + }
  354 +
  355 + getStatus() {
  356 + return this.status;
  357 + }
  358 +
  359 + getPlayer() {
  360 + return this.avPlayer != undefined
  361 + }
  362 +
  363 + initProgress(time: number) {
  364 + if (this.onTimeUpdate) {
  365 + this.onTimeUpdate(time, this.duration);
  366 + }
  367 + }
  368 +
  369 + resetProgress() {
  370 + this.seekTime = 0;
  371 + this.duration = 0;
  372 + }
  373 +
  374 + onVolumeActionStart(event: GestureEvent) {
  375 + this.positionY = event.offsetY;
  376 + }
  377 +
  378 + onBrightActionStart(event: GestureEvent) {
  379 + this.positionY = event.offsetY;
  380 + }
  381 +
  382 + volume: number = 1
  383 +
  384 + onVolumeActionUpdate(event: GestureEvent) {
  385 + if (!this.avPlayer) {
  386 + return
  387 + }
  388 + if (this.avPlayerStatus != prepared &&
  389 + this.avPlayerStatus != started &&
  390 + this.avPlayerStatus != paused &&
  391 + this.avPlayerStatus != completion) {
  392 + return;
  393 + }
  394 + let changeVolume = (event.offsetY - this.positionY) / 300;
  395 + let currentVolume = this.volume - changeVolume;
  396 + if (currentVolume > 1) {
  397 + currentVolume = 1;
  398 + }
  399 + if (currentVolume <= 0) {
  400 + currentVolume = 0;
  401 + }
  402 + this.volume = currentVolume;
  403 + this.avPlayer?.setVolume(this.volume);
  404 + this.positionY = event.offsetY;
  405 + if (this.onVolumeUpdate) {
  406 + this.onVolumeUpdate(this.volume);
  407 + }
  408 + console.log("volume : " + this.volume)
  409 + }
  410 +
  411 + onBrightActionUpdate(event: GestureEvent) {
  412 + // if (!this.playerThis.volumeShow) {
  413 + // this.playerThis.brightShow = true;
  414 + // let changeBright = (this.positionY - event.offsetY) / globalThis.screenHeight;
  415 + // let currentBright = this.playerThis.bright + changeBright;
  416 + // let brightMinFlag = currentBright <= 0;
  417 + // let brightMaxFlag = currentBright > 1;
  418 + // this.playerThis.bright = brightMinFlag ? 0 :
  419 + // (brightMaxFlag ? 1 : currentBright);
  420 + // this.setBright();
  421 + // this.positionY = event.offsetY;
  422 + // }
  423 + }
  424 +
  425 + onActionEnd() {
  426 + setTimeout(() => {
  427 + this.positionY = 0;
  428 + }, 200);
  429 + }
  430 +
  431 + watchStatus() {
  432 + console.log('watchStatus', this.status)
  433 + if (this.onStatusChange) {
  434 + this.onStatusChange(this.status)
  435 + }
  436 + // if (this.status === PlayConstants.STATUS_START) {
  437 + // globalThis.windowClass.setWindowKeepScreenOn(true);
  438 + // } else {
  439 + // globalThis.windowClass.setWindowKeepScreenOn(false);
  440 + // }
  441 + }
  442 +
  443 + playError(msg?: string) {
  444 + prompt.showToast({
  445 + duration: 3000,
  446 + message: msg ? msg : "请检查地址输入正确且网络正常"
  447 + });
  448 + }
  449 +
  450 + setStartTime(time?: number) {
  451 + this.startTime = time ?? 0;
  452 + }
  453 +}
@@ -134,6 +134,10 @@ export class WDPlayerController { @@ -134,6 +134,10 @@ export class WDPlayerController {
134 this.surfaceId = controller.getXComponentSurfaceId() 134 this.surfaceId = controller.getXComponentSurfaceId()
135 } 135 }
136 136
  137 + setSurfaceId(surfaceId: string) {
  138 + this.surfaceId = surfaceId
  139 + }
  140 +
137 async firstPlay(url: string) { 141 async firstPlay(url: string) {
138 this.url = url; 142 this.url = url;
139 if (this.avPlayer == null) { 143 if (this.avPlayer == null) {
@@ -2,6 +2,7 @@ import componentUtils from '@ohos.arkui.componentUtils'; @@ -2,6 +2,7 @@ import componentUtils from '@ohos.arkui.componentUtils';
2 import { WDPlayerController } from '../controller/WDPlayerController' 2 import { WDPlayerController } from '../controller/WDPlayerController'
3 import { WindowModel } from 'wdKit'; 3 import { WindowModel } from 'wdKit';
4 import { Logger } from '../utils/Logger'; 4 import { Logger } from '../utils/Logger';
  5 +import { enableAliPlayer } from '../utils/GlobalSetting';
5 6
6 class Size { 7 class Size {
7 width: Length = "100%"; 8 width: Length = "100%";
@@ -74,8 +75,9 @@ export struct WDPlayerRenderLiveView { @@ -74,8 +75,9 @@ export struct WDPlayerRenderLiveView {
74 Row() { 75 Row() {
75 // 设置为“surface“类型时XComponent组件可以和其他组件一起进行布局和渲染。 76 // 设置为“surface“类型时XComponent组件可以和其他组件一起进行布局和渲染。
76 XComponent({ 77 XComponent({
77 - id: 'xComponentId',  
78 - type: 'surface', 78 + id: enableAliPlayer ? this.insId : 'xComponentId',
  79 + type: XComponentType.SURFACE,
  80 + libraryname: enableAliPlayer ? "premierlibrary" : undefined,
79 controller: this.xComponentController 81 controller: this.xComponentController
80 }) 82 })
81 .onLoad(async (event) => { 83 .onLoad(async (event) => {
@@ -87,7 +89,11 @@ export struct WDPlayerRenderLiveView { @@ -87,7 +89,11 @@ export struct WDPlayerRenderLiveView {
87 surfaceWidth: 1920, 89 surfaceWidth: 1920,
88 surfaceHeight: 720 90 surfaceHeight: 720
89 }); 91 });
  92 + if (enableAliPlayer) {
  93 + this.playerController?.setSurfaceId(this.insId)
  94 + } else {
90 this.playerController?.setXComponentController(this.xComponentController) 95 this.playerController?.setXComponentController(this.xComponentController)
  96 + }
91 if (this.onLoad) { 97 if (this.onLoad) {
92 this.onLoad(event) 98 this.onLoad(event)
93 } 99 }
@@ -2,6 +2,7 @@ import componentUtils from '@ohos.arkui.componentUtils'; @@ -2,6 +2,7 @@ import componentUtils from '@ohos.arkui.componentUtils';
2 import { WDPlayerController } from '../controller/WDPlayerController' 2 import { WDPlayerController } from '../controller/WDPlayerController'
3 import { WindowModel } from 'wdKit'; 3 import { WindowModel } from 'wdKit';
4 import { Logger } from '../utils/Logger'; 4 import { Logger } from '../utils/Logger';
  5 +import { enableAliPlayer } from '../utils/GlobalSetting';
5 6
6 class Size { 7 class Size {
7 width: Length = "100%"; 8 width: Length = "100%";
@@ -73,8 +74,9 @@ export struct WDPlayerRenderVLiveView { @@ -73,8 +74,9 @@ export struct WDPlayerRenderVLiveView {
73 Row() { 74 Row() {
74 // 设置为“surface“类型时XComponent组件可以和其他组件一起进行布局和渲染。 75 // 设置为“surface“类型时XComponent组件可以和其他组件一起进行布局和渲染。
75 XComponent({ 76 XComponent({
76 - id: 'xComponentId',  
77 - type: 'surface', 77 + id: enableAliPlayer ? this.insId : 'xComponentId',
  78 + type: XComponentType.SURFACE,
  79 + libraryname: enableAliPlayer ? "premierlibrary" : undefined,
78 controller: this.xComponentController 80 controller: this.xComponentController
79 }) 81 })
80 .onLoad(async (event) => { 82 .onLoad(async (event) => {
@@ -84,7 +86,11 @@ export struct WDPlayerRenderVLiveView { @@ -84,7 +86,11 @@ export struct WDPlayerRenderVLiveView {
84 surfaceWidth: 1920, 86 surfaceWidth: 1920,
85 surfaceHeight: 1080 87 surfaceHeight: 1080
86 }); 88 });
  89 + if (enableAliPlayer) {
  90 + this.playerController?.setSurfaceId(this.insId)
  91 + } else {
87 this.playerController?.setXComponentController(this.xComponentController) 92 this.playerController?.setXComponentController(this.xComponentController)
  93 + }
88 if (this.onLoad) { 94 if (this.onLoad) {
89 this.onLoad(event) 95 this.onLoad(event)
90 } 96 }
@@ -2,6 +2,7 @@ import componentUtils from '@ohos.arkui.componentUtils'; @@ -2,6 +2,7 @@ import componentUtils from '@ohos.arkui.componentUtils';
2 import { WDPlayerController } from '../controller/WDPlayerController' 2 import { WDPlayerController } from '../controller/WDPlayerController'
3 import { WindowModel } from 'wdKit'; 3 import { WindowModel } from 'wdKit';
4 import { Logger } from '../utils/Logger'; 4 import { Logger } from '../utils/Logger';
  5 +import { enableAliPlayer } from '../utils/GlobalSetting';
5 6
6 class Size { 7 class Size {
7 width: Length = "100%"; 8 width: Length = "100%";
@@ -75,6 +76,7 @@ export struct WDPlayerRenderView { @@ -75,6 +76,7 @@ export struct WDPlayerRenderView {
75 XComponent({ 76 XComponent({
76 id: this.insId, 77 id: this.insId,
77 type: XComponentType.SURFACE, 78 type: XComponentType.SURFACE,
  79 + libraryname: enableAliPlayer ? "premierlibrary" : undefined,
78 controller: this.xComponentController 80 controller: this.xComponentController
79 }) 81 })
80 .onLoad(async (event) => { 82 .onLoad(async (event) => {
@@ -83,7 +85,11 @@ export struct WDPlayerRenderView { @@ -83,7 +85,11 @@ export struct WDPlayerRenderView {
83 surfaceWidth: 1920, 85 surfaceWidth: 1920,
84 surfaceHeight: 1080 86 surfaceHeight: 1080
85 }); 87 });
  88 + if (enableAliPlayer) {
  89 + this.playerController?.setSurfaceId(this.insId)
  90 + } else {
86 this.playerController?.setXComponentController(this.xComponentController) 91 this.playerController?.setXComponentController(this.xComponentController)
  92 + }
87 if (this.onLoad) { 93 if (this.onLoad) {
88 this.onLoad(event) 94 this.onLoad(event)
89 } 95 }
  1 +import { AliPlayerGlobalSettings, AliPlayer } from 'premierlibrary';
  2 +
  3 +import fs from '@ohos.file.fs';
  4 +import common from '@ohos.app.ability.common';
  5 +import { error } from 'premierlibrary/src/main/ets/com/aliyun/player/IPlayer';
  6 +import { BusinessError } from '@kit.BasicServicesKit';
  7 +
  8 +let currentContext = getContext() as common.UIAbilityContext
  9 +
  10 +export function initGlobalPlayerSettings(context?: common.UIAbilityContext) {
  11 +
  12 + AliPlayerGlobalSettings.setUseHttp2(true);
  13 +
  14 + let filesDir = (context != undefined ? context : currentContext).filesDir;
  15 + let cachePath = filesDir + "/player-cache"
  16 +
  17 + fs.stat(cachePath).catch((error: BusinessError) => {
  18 + if (error.code = 13900002) {
  19 + fs.mkdirSync(cachePath)
  20 + }
  21 + })
  22 +
  23 + AliPlayerGlobalSettings.enableLocalCache(true,1 * 1024, cachePath)
  24 +
  25 + AliPlayerGlobalSettings.setCacheFileClearConfig(3 * 24 * 6, 1024, 300)
  26 +}
  27 +
  28 +export function setupPlayerConfig(player: AliPlayer) {
  29 + let config = player.getConfig()
  30 + if (config) {
  31 + config.mMaxDelayTime = 500
  32 + config.mMaxBufferDuration = 50000
  33 + config.mHighBufferDuration = 3000
  34 + config.mStartBufferDuration = 50
  35 + player.setConfig(config)
  36 + }
  37 +}
  38 +
  39 +/*
  40 + * 开启前注意:
  41 + * 1、配置好包名对应的license文件
  42 + * 2、页面组件播放器控制器使用WDAliPlayerController
  43 + * 3、WDAliListPlayerController 暂时由于SDK问题,不能使用
  44 + * 4、
  45 + * */
  46 +export const enableAliPlayer = false
@@ -9,6 +9,23 @@ @@ -9,6 +9,23 @@
9 "2in1" 9 "2in1"
10 ], 10 ],
11 "deliveryWithInstall": true, 11 "deliveryWithInstall": true,
12 - "pages": "$profile:main_pages" 12 + "pages": "$profile:main_pages",
  13 +
  14 + "metadata": [
  15 + {
  16 + "name": "com.aliyun.alivc_license.licensekey",
  17 + // "value": "MoCTfuQ391Z01mNqG8f8786e23c8a457a8ff8d5faedc1040c"
  18 + "value": "KoETnmCmxJ1e1ZXDj0eb2ddb6c81c4cb7b9912df65e6d8eb2"
  19 + },
  20 + {
  21 + "name": "com.aliyun.alivc_license.licensefile",
  22 + // "value": "license.crt"
  23 + "value": "pre-license.crt"
  24 + },
  25 + {
  26 + "name": "com.aliyun.alivc_license.service_env",
  27 + "value": "PreRelease"
  28 + }
  29 + ]
13 } 30 }
14 } 31 }
  1 +-----BEGIN ALI VIDEO CERT-----
  2 +LmlsQS5jaUwAAWU1MGY1NWU1Y2U1MzIxMDc5MjQ4ZjUzNGQ2ZjVmZmQ2ZmY1MTFmM
  3 +WMzZTlmZDU4NjUxNmU4YmI0NmMxNzM0MTU1OTBjYzQyY2Y4NGY4Y2U2MGZmYjMzMG
  4 +Q5NTQ1NjFmMGMxNzBjMmUyZGQ5MjYwNjY2YjVlN2Y2YTlhMjZhMzc0YjNhNjExN2N
  5 +lYzRlNGYzMGIxODViMmRlOTVhNzU1Nzg2YzY4MzhkYTY1YWI5NTUzMjQyNjRkN2Q0
  6 +OGE0OTExZjFkYzM5MzllZGQ2YjE2OThkNjJjMGI3ZmUwNDRkOGMwYTI0ZTgzZTRiM
  7 +jUwMTk2MDgwNWFkYzBmMGMwNDU3MDE5ZGI0NDNjYzRiNjc3MjRhMTg5YjAyYmU1YT
  8 +E4NDg1ZWQ4NWRmZDQxYzVkZTUzOTUyNmZiOWNiODNjNTE5MWZhMWE4N2E3YjE3M2I
  9 +xY2I4NzI2YTFiZDFjZjBkZTNlNzM2ZmU3NmFmMjQyOWRlY2FjNTUzYjdhZmFjNDM1
  10 +NTRhNDYwY2RkNWE2NGFmZDg5N2ZmYmVjMWQ3NTc0MDdlOGM2ODBkYzMyYjM1YzU0Z
  11 +Dk1N2MyMTk2YjlmYzEwNjA0YTVmZGQ1Yzg0OTE1N2VkZDNiYjk4OTc4YjZjMGY1OD
  12 +Q4MDY5MjQzMTQzZmMyZDA1ZGJiNTJjMjVhZjMwMWFjYTNkAAAB1u6ksgCgo8C07iY
  13 +q52y6BA6nGYLr+YxZCDTYa0zPm21WZhNlUYE8xR1KKPxoOfhgADCG7FubFonJ5pyD
  14 +2+O7g21xWr3CbYQ1S1D/qWE9pYtIoIUl3USIr8pfRQz2/Lk4TUPO/VzgAWeQrbclC
  15 +wgz50pvVzVAwGjBQfofHlCMO6iIbgSazoopOZSeDfOULs7dPkIOfjeSm1ZMCpytgh
  16 +SKCsd0GwaV+yWn+Uk2DOLafFk2logpRGmQzxcZ/K+vJuedUPHzMSRV8VfXc86wix9
  17 +Tx1sokTb9Xt3wqYgbO/5jn2RhOdBYruFUOrFt3LIp1rKj8XngtwI7Cjr7oBAlEXMf
  18 +Uk2A1s/+AAABZB0FG6sG6bbq5JZuwpbmlC7QuD/rUW5iJavqQwZbylmgDuHTZKe22
  19 +mpbwLrw+3w0j9WAsytGn1C07nnmdjzJGe7oujnqOEgUSId9kkBN898rVMjfMy0ckt
  20 +QgBLtxy6nHvgXLbxUzG4rXHccWAwyTGnEfwNl3FRSuB8jGPewQvrV/HyRKMY7MASv
  21 +EA2uo6NGxLfkz+YrqKjFywqsBmTACkE7kJzL2MoNJ6hfJkKl92Z1+HvpwJEV7EdwN
  22 +Qd7MoB+Jd2gF9YLbnk0h+h+d+aI9tIoM8CksdkHsCLLAONvi7LwwN/RcoytfKts8i
  23 +YQ+b5do3+z/ybD/XZVSPswWmuW1BqEAAAGNchb17gAAAFMAAAAgZ2E3ODYwZGNhMT
  24 +g1NDQ0MTlhNTMzNzBhYTQ4ZGIzZDEAAAABAAAAJwAAAAAAAABAAAAAG2NvbS5hbGl
  25 +5dW4ucGxheWVyLm9ob3NfZGVtbwAAAAEAAAEFAAAAAgAAAAAAAABAAAAj8QAAAZiU
  26 +tdAAAQAAAOgAAAABAAAACAAAABgAAE4hAAABjXIW8ngAAAGYlLXQAAAAAAAAAAAYA
  27 +ABOIgAAAY1yFvJ4AAABmJS10AAAAAAAAAAAGAAATiMAAAGNchbyeAAAAZiUtdAAAA
  28 +AAAAAAABgAAE4kAAABjXIW8ngAAAGYlLXQAAAAAAAAAAAYAABOJQAAAY1yFvJ4AAA
  29 +BmJS10AAAAAAAAAAAGAAATiYAAAGNchbyeAAAAZiUtdAAAAAAAAAAABgAAE4nAAAB
  30 +jXIW8ngAAAGYlLXQAAAAAAAAAAAYAABOhQAAAY1yFvJ4AAABmJS10AAAAAAA
  31 +-----END ALI VIDEO CERT-----