HarmonyOS 鸿蒙Next AVPlayer切换surfaceId 异常

发布于 1周前 作者 sinazl 来自 鸿蒙OS

HarmonyOS 鸿蒙Next AVPlayer切换surfaceId 异常

1、AVPlayer先绑定竖屏surfaceId显示正常,

2、点击态全屏模态转场的XComponent 切换AVPlayer的surfaceId显示异常(屏幕花屏什么的)

2 回复

1.surfaceId支持在initialized状态下设置。也支持在prepared/playing/paused/completed/stopped状态下重新设置,重新设置时确保已经在initialized状态下进行设置,否则重新设置失败,重新设置后视频播放在新的窗口渲染。

2.切换不需要调用avPlayer.reset(),以下是切换的简单示例,请参考:

import { media } from '[@kit](/user/kit).MediaKit';

import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';

const TAG = 'AVPlayerDemo';

[@Entry](/user/Entry)

[@Component](/user/Component)

struct Index {

 private surfaceId: string = ''; // surfaceId,用于关联XComponent与视频播放器

 private mXComponentController: XComponentController = new XComponentController();

 private avPlayer: media.AVPlayer | undefined = undefined;

 private surfaceId2: string = ''; // surfaceId,用于关联XComponent2与视频播放器

 private mXComponentController2: XComponentController = new XComponentController();

 aboutToAppear(): void {

   //创建avplayer

   this.createAVPlayer()

 }

 createAVPlayer() {

   media.createAVPlayer().then((video: media.AVPlayer) => {

     if (video != null) {

       this.avPlayer = video;

       this.setAVPlayerCallback(this.avPlayer);

       this.avPlayer.url = 'http://fotiletest2.oss-cn-hangzhou.aliyuncs.com/f86ee6ff04f94c4d922936faedbfca06';

       console.info(TAG,'createAVPlayer success');

     } else {

       console.error(TAG,'createAVPlayer fail');

     }

   }).catch((error: BusinessError) => {

     console.error(TAG,`AVPlayer catchCallback, error message:${error.message}`);

   });

 }

 // 注册avplayer回调函数

 setAVPlayerCallback(avPlayer: media.AVPlayer) {

   avPlayer.on('timeUpdate', (time: number) => {

     console.info(TAG,`AVPlayer timeUpdate. time is ${time}`);

   })

   // error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程

   avPlayer.on('error', (err: BusinessError) => {

     console.error(TAG,`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);

     avPlayer.reset(); // 调用reset重置资源,触发idle状态

   })

   // 状态机变化回调函数

   avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {

     switch (state) {

       case 'idle': // 成功调用reset接口后触发该状态机上报

         console.info(TAG,'AVPlayer state idle called.');

         break;

       case 'initialized': // avplayer 设置播放源后触发该状态上报

         console.info(TAG,'AVPlayer state initialized called.');

         avPlayer.surfaceId = this.surfaceId;

         avPlayer.prepare();

         break;

       case 'prepared': // prepare调用成功后上报该状态机

         console.info(TAG,'AVPlayer state prepared called.');

         avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X)

         avPlayer.seek(1, media.SeekMode.SEEK_PREV_SYNC)

         avPlayer.play();

         break;

       case 'completed': // prepare调用成功后上报该状态机

         console.info(TAG,'AVPlayer state completed called.');

         break;

       case 'playing': // play成功调用后触发该状态机上报

         console.info(TAG,'AVPlayer state playing called.');

         break;

       case 'paused': // pause成功调用后触发该状态机上报

         console.info(TAG,'AVPlayer state paused called.');

         break;

       case 'stopped': // stop接口成功调用后触发该状态机上报

         console.info(TAG,'AVPlayer state stopped called.');

         break;

       case 'released':

         console.info(TAG,'AVPlayer state released called.');

         break;

       default:

         console.info(TAG,'AVPlayer state unknown called.');

         break;

     }

   })

 }

 build() {

   Column() {

     XComponent({

       id: 'test',

       type: XComponentType.SURFACE,

       controller: this.mXComponentController

     })

       .onLoad(() => {

         this.surfaceId = this.mXComponentController.getXComponentSurfaceId();

       })

       .width('100%')

       .height(260)

     Button('窗口1播放')

       .width(200)

       .height(50)

       .onClick(() => {

         if (this.avPlayer) {

           this.avPlayer.surfaceId = this.surfaceId

         }

       });

     Button('窗口2播放')

       .width(200)

       .height(50)

       .onClick(() => {

         if (this.avPlayer) {

           this.avPlayer.surfaceId = this.surfaceId2

         }

       });

     XComponent({

       id: 'test2',

       type: XComponentType.SURFACE,

       controller: this.mXComponentController2

     })

       .onLoad(() => {

         this.mXComponentController2.setXComponentSurfaceRect({

           offsetX:0,

           offsetY:0,

           surfaceWidth: 1920,

           surfaceHeight: 1080

         })

         this.surfaceId2 = this.mXComponentController2.getXComponentSurfaceId();

       })

       .width('100%')

       .height(260)

   }

   .zIndex(1)

   .width('100%')

   .height('100%')

 }

}

针对HarmonyOS鸿蒙Next AVPlayer切换surfaceId异常的问题,这通常发生在跨页面视频播放场景中,当尝试更换XComponent后,新的surfaceId无法与已有的AVPlayer实例成功绑定。以下是一些专业的解决方案:

  1. 全局管理AVPlayer

    • 将AVPlayer作为全局单例变量存储,在需要切换surfaceId时,从全局获取AVPlayer实例,并更新其surfaceId。
  2. 确保surfaceId有效性

    • 在设置surfaceId前,确保该surfaceId是有效且当前可用的,避免设置无效的surfaceId导致异常。
  3. 监听状态变化

    • 通过监听AVPlayer的状态变化,确保在正确的时机进行surfaceId的切换,避免在AVPlayer未准备好时进行操作。
  4. 优化内存管理

    • 确保视频播放时内存管理得当,避免内存泄漏和过度占用内存,这有助于减少切换surfaceId时的异常。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部