HarmonyOS VideoController缺少相应方法

VideoController提供了播放控制功能,比如开始播放、暂停播放,停止播放,设置播放位置,切换还原全屏模式。但是无法获取相关属性状态,如当前是否在播放中、当前播放时刻是否全屏模式。

HarmonyOS
2024-12-25 12:23:09
浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
aquaa

参考示例如下:

1、AVPlayerDemo.ets

import media from '@ohos.multimedia.media';
import { BusinessError } from '@ohos.base';
import pipWindow from '@ohos.PiPWindow';
import { display, window } from '@kit.ArkUI';
import { GlobalContext } from '../util/GlobalContext';
import { avSession } from '@kit.AVSessionKit';
import { audio } from '@kit.AudioKit';
import { image } from '@kit.ImageKit';
import { abilityAccessCtrl, PermissionRequestResult, Permissions, WantAgent, wantAgent } from '@kit.AbilityKit';
import { backgroundTaskManager } from '@kit.BackgroundTasksKit';

@Entry
@Component
struct AVPlayerDemo {
  @Watch('setWindowLayOut') @State isFullScreen: boolean = false;
  @State isLandscape: boolean = false;
  @State isVideo: boolean = true;
  @State isOpacity: boolean = false;
  @State isPlay: boolean = false;
  @State currentTime: number = 0;
  @State durationTime: number = 0;
  @State durationStringTime: string = '00:00';
  @State currentStringTime: string = '00:00';
  @State flag: boolean = false;
  @State videoFiles: media.AVFileDescriptor[] = [];
  @State audioFiles: media.AVFileDescriptor[] = [];
  @State sourceFiles: media.AVFileDescriptor[] = [];
  @State currentIndex: number = 0;
  @State speed: number = media.PlaybackSpeed.SPEED_FORWARD_1_00_X;
  private avPlayer: media.AVPlayer | undefined = undefined;
  private xComponentController = new XComponentController();
  private surfaceID: string = '';
  private readonly OPERATE_STATE: Array<string> = ['prepared', 'playing', 'paused', 'completed'];
  private pipController: pipWindow.PiPController | undefined = undefined;
  private windowClass: window.Window = GlobalContext.getContext().getObject('windowClass') as window.Window;
  private currentAVSession: avSession.AVSession | undefined = undefined;
  private curSessionId: string = '';
  private avsessionController: avSession.AVSessionController | undefined = undefined;
  private curPixelMap: image.PixelMap | undefined = undefined;
  private playbackState: avSession.AVPlaybackState = {
    state: avSession.PlaybackState.PLAYBACK_STATE_PLAY, // 播放状态
    position: {
      elapsedTime: 0, // 已经播放的位置,以ms为单位
      updateTime: 0, // 应用更新当前位置的时间戳,以ms为单位
    },
    speed: this.speed, // 可选,默认是1.0,播放的倍速,按照应用内支持的speed进行设置,系统不做校验
    // bufferedTime: 14000, // 可选,资源缓存的时间,以ms为单位
    duration: 0, // 资源的时长,以ms为单位
    loopMode: avSession.LoopMode.LOOP_MODE_SEQUENCE, // 循环模式
  };

  setWindowLayOut() {
    // 监听全屏事件,设置沉浸式窗口
    this.windowClass.setWindowLayoutFullScreen(this.isFullScreen);
  }

  aboutToAppear(): void {
    this.initFiles();
    // 初始化AVPlayer
    this.createAVPlayer();
    // 初始化画中画
    this.createPipWindow();
    // 初始化AVSession
    this.createAVSession();
    this.saveRawFileToPixelMap('first.png')
    this.reset(true)
    try {
      // 监听窗口尺寸变化
      this.windowClass.on('windowSizeChange', (data) => {
        console.info('AVPlayerDemo Succeeded in enabling the listener for window size changes. Data: ' +
        JSON.stringify(data));
        let orientation = display.getDefaultDisplaySync().orientation;
        // 横屏
        if (orientation == display.Orientation.LANDSCAPE || orientation == display.Orientation.LANDSCAPE_INVERTED) {
          this.isLandscape = true;
        }
        // 竖屏
        if (orientation == display.Orientation.PORTRAIT || orientation == display.Orientation.PORTRAIT_INVERTED) {
          this.isLandscape = false;
        }
      });
    } catch (exception) {
      console.error('AVPlayerDemo Failed to enable the listener for window size changes. Cause: ' +
      JSON.stringify(exception));
    }
  }

  aboutToDisappear(): void {
    if (this.avPlayer) {
      this.avPlayer.off('timeUpdate');
      this.avPlayer.off('seekDone');
      this.avPlayer.off('error');
      this.avPlayer.off('stateChange');
      this.avPlayer.release();
    }
    if (this.currentAVSession) {
      this.currentAVSession.off('play');
      this.currentAVSession.off('pause');
      this.currentAVSession.off('stop');
      this.currentAVSession.off('playNext');
      this.currentAVSession.off('playPrevious');
      this.currentAVSession.off('fastForward');
      this.currentAVSession.off('rewind');
      this.currentAVSession.off('playFromAssetId');
      this.currentAVSession.off('seek');
      this.currentAVSession.off('setSpeed');
      this.currentAVSession.deactivate();
      this.currentAVSession.destroy();
    }
    try {
      this.windowClass.off('windowSizeChange');
    } catch (exception) {
      console.error('AVPlayerDemo Failed to disable the listener for window size changes. Cause: ' +
      JSON.stringify(exception));
    }
    this.stopContinuousTask();
  }

  build() {
    Column() {
      if (!this.isFullScreen) {
        Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceAround }) {
          Column() {
            Text('视频播放')
              .fontColor(this.isVideo ? Color.Blue : Color.Black)
              .fontSize(16)
              .fontWeight(this.isVideo ? 500 : 400)
              .lineHeight(22)
              .margin({ top: 17, bottom: 7 })
            Divider()
              .strokeWidth(2)
              .color('#007DFF')
              .opacity(this.isVideo ? 1 : 0)
          }
          .onClick(() => {
            this.isVideo = true
            this.reset(true);
          })

          Column() {
            Text('音频播放')
              .fontColor(!this.isVideo ? Color.Blue : Color.Black)
              .fontSize(16)
              .fontWeight(!this.isVideo ? 500 : 400)
              .lineHeight(22)
              .margin({ top: 17, bottom: 7 })
            Divider()
              .strokeWidth(2)
              .color('#007DFF')
              .opacity(!this.isVideo ? 1 : 0)
          }
          .onClick(() => {
            this.isVideo = false
            this.reset(true);
          })
        }
        .margin({ bottom: '8vp' })
      }

      Flex({
        direction: FlexDirection.Column,
        justifyContent: this.isFullScreen ? FlexAlign.Center : FlexAlign.Start
      }) {
        if (this.isVideo) {
          this.VideoPlayer()
        } else {
          this.AudioPlayer()
        }

        if (!this.isFullScreen) {
          this.Buttons();
        }
      }
      .width('100%')
      .height('100%')
      .backgroundColor(this.isFullScreen ? Color.Black : Color.White)

    }
    .width('100%')
    .height('100%')
  }

  @Builder
  Buttons() {
    Column() {
      Scroll() {
        GridRow({
          columns: 2,
          gutter: { x: 5, y: 10 },
          direction: GridRowDirection.Row
        }) {
          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('播放').width(140).onClick(() => {
              this.play();
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('暂停').width(140).onClick(() => {
              this.isPlay = false;
              if (this.avPlayer) {
                this.avPlayer.pause();
              }
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('停止').width(140).onClick(() => {
              this.stopPlay();
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('跳转5秒位置').width(140).onClick(() => {
              this.setSeek(5, 0);
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('进入全屏').width(140).onClick(() => {
              this.isFullScreen = true;
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('0.75倍速').width(140).onClick(() => {
              this.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_0_75_X);
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('1倍速').width(140).onClick(() => {
              this.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X);
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('1.25倍速').width(140).onClick(() => {
              this.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_25_X);
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('1.75倍速').width(140).onClick(() => {
              this.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_75_X);
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('2倍速').width(140).onClick(() => {
              this.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X);
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('快进5秒').width(140).onClick(() => {
              this.setSeek(5);
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('快退5秒').width(140).onClick(() => {
              this.setSeek(-5);
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('上一个').width(140).onClick(() => {
              this.goToNextOrPre(-1);
            });
          }

          GridCol({ span: 1, offset: 0, order: 0 }) {
            Button('下一个').width(140).onClick(() => {
              this.goToNextOrPre(1);
            });
          }

          if (this.isVideo) {
            GridCol({ span: 1, offset: 0, order: 0 }) {
              Button('开启画中画').width(140).onClick(() => {
                this.startPipWindow();
              });
            }

            GridCol({ span: 1, offset: 0, order: 0 }) {
              Button('关闭画中画').width(140).onClick(() => {
                this.stopPipWindow();
              });
            }
          }
        }
        .margin({ bottom: 20, top: 20 })
        .borderRadius(20)
      }
      .scrollBar(BarState.Off)
    }
  }

  @Builder
  VideoPlayer() {
    Stack({
      alignContent: this.isFullScreen ? (this.isLandscape ? Alignment.Bottom : Alignment.Center) : Alignment.Bottom
    }) {
      Stack() {
        if (!this.isPlay) {
          Image($r('app.media.ic_public_play'))
            .width(50)
            .height(50)
            .zIndex(2)
            .onClick(() => {
              this.play();
            });
        }

        Column() {
          XComponent({
            id: '',
            type: XComponentType.SURFACE,
            libraryname: '',
            controller: this.xComponentController
          })
            .onLoad(() => {
              this.xComponentController.setXComponentSurfaceSize({
                surfaceWidth: 1920,
                surfaceHeight: 1080
              });
              this.surfaceID = this.xComponentController.getXComponentSurfaceId();
            })
            .width('100%')
            .height('100%');
        }
        .zIndex(1)
        .onClick(() => {
          this.playOrPause();
        })
      }
      .width('100%')
      .height(this.isFullScreen ? (this.isLandscape ? '100%' : 260) : '100%')

      this.PlayControl()
    }
    .height(this.isFullScreen ? '100%' : 260)
    .backgroundColor(Color.Black)
    .width('100%')
  }

  @Builder
  AudioPlayer() {
    Stack({ alignContent: this.isFullScreen ? Alignment.Center : Alignment.Bottom }) {
      Image($r('app.media.ic_camera_story_playing')).objectFit(ImageFit.Contain)
      this.PlayControl()
    }
    .height(260)
    .backgroundImage($r('app.media.background'), ImageRepeat.NoRepeat)
    .width('100%')
  }

  @Builder
  PlayControl() {
    Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
      Image($r('app.media.ic_previous'))
        .width('20vp')
        .height('20vp')
        .onClick(() => {
          this.goToNextOrPre(-1)
        });
      Image(this.isPlay ? $r('app.media.ic_pause') : $r('app.media.ic_play'))
        .width('20vp')
        .height('20vp')
        .onClick(() => {
          this.iconOnclick();
        });
      Image($r('app.media.ic_next'))
        .width('20vp')
        .height('20vp')
        .onClick(() => {
          this.goToNextOrPre(1)
        });
      Text(this.currentStringTime)
        .fontSize('14vp')
        .fontColor(Color.White)
        .margin({ left: '2vp' })
      Slider({
        value: this.currentTime,
        step: 1,
        min: 0,
        max: this.durationTime,
        style: SliderStyle.OutSet
      })
        .blockColor(Color.White)
        .width('50%')
        .trackColor(Color.Gray)
        .selectedColor(Color.White)
        .showSteps(false)
        .showTips(false)
        .trackThickness(this.isOpacity ? 2 : 4)
        .onChange((value: number, mode: SliderChangeMode) => {
          this.sliderOnchange(value, mode);
        });
      Text(this.durationStringTime)
        .fontSize('14vp')
        .fontColor(Color.White)
        .margin({ left: '2vp', right: '2vp' })
      Image($r('app.media.ic_public_reduce'))
        .width('20vp')
        .height('20vp')
        .onClick(() => {
          this.isFullScreen = !this.isFullScreen
        });
    }
    .zIndex(2)
    .padding({ right: '2vp' })
    .opacity(this.isOpacity ? 0.7 : 1)
    .width('100%')
    .offset({ x: 0, y: this.isFullScreen ? (this.isLandscape ? 0 : 110) : 0 })
    .backgroundBlurStyle(BlurStyle.Thin, { colorMode: ThemeColorMode.DARK })
  }

  createPipWindow() {
    let config: pipWindow.PiPConfiguration = {
      context: getContext(this),
      componentController: this.xComponentController,
      // navigationId: navId,
      templateType: pipWindow.PiPTemplateType.VIDEO_PLAY,
      contentWidth: 800,
      contentHeight: 600,
    };

    pipWindow.create(config).then((data: pipWindow.PiPController) => {
      console.info(`AVPlayerDemo Succeeded in creating pip controller. Data:${data}`);
      this.pipController = data;
      this.setPipWindowCallback(data)
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo Failed to create pip controller. Cause:${err.code}, message:${err.message}`);
    });
  }

  // 注册PipWindow回调函数
  setPipWindowCallback(pipController: pipWindow.PiPController) {
    // 注册PipWindow生命周期状态监听
    pipController.on('stateChange', (state: pipWindow.PiPState, reason: string) => {
      let curState: string = '';
      switch (state) {
        case pipWindow.PiPState.ABOUT_TO_START:
          curState = 'ABOUT_TO_START';
          break;
        case pipWindow.PiPState.STARTED:
          curState = 'STARTED';
          break;
        case pipWindow.PiPState.ABOUT_TO_STOP:
          curState = 'ABOUT_TO_STOP';
          break;
        case pipWindow.PiPState.STOPPED:
          pipController.setAutoStartEnabled(false)
          curState = 'STOPPED';
          break;
        case pipWindow.PiPState.ABOUT_TO_RESTORE:
          curState = 'ABOUT_TO_RESTORE';
          break;
        case pipWindow.PiPState.ERROR:
          curState = 'ERROR';
          break;
        default:
          break;
      }
      console.info('AVPlayerDemo pipController stateChange:' + curState + ' reason:' + reason);
    });
    // 注册PipWindow控制事件监听
    pipController.on('controlPanelActionEvent', (event: pipWindow.PiPActionEventType) => {
      switch (event) {
        case 'playbackStateChanged':
        // 开始或停止视频
          this.playOrPause();
          break;
        case 'nextVideo':
        // 切换到下一个视频
          this.goToNextOrPre(1);
          break;
        case 'previousVideo':
        // 切换到上一个视频
          this.goToNextOrPre(-1);
          break;
        default:
          break;
      }
      console.info('AVPlayerDemo pipController registerActionEventCallback, event:' + event);
    });
  }

  startPipWindow() {
    if (this.pipController) {
      // 设置是否需要在返回桌面时自动启动画中画
      this.pipController.setAutoStartEnabled(true)
      this.pipController.startPiP().then(() => {
        // this.play();
        console.info(`AVPlayerDemo Succeeded in starting pip.`);
      }).catch((err: BusinessError) => {
        console.error(`AVPlayerDemo Failed to start pip. Cause:${err.code}, message:${err.message}`);
      });
    }
  }

  stopPipWindow() {
    if (this.pipController) {
      this.pipController.stopPiP().then(() => {
        console.info(`AVPlayerDemo Succeeded in stop pip.`);
      }).catch((err: BusinessError) => {
        console.error(`AVPlayerDemo Failed to stop pip. Cause:${err.code}, message:${err.message}`);
      });
    }
  }

  // 注册avplayer回调函数
  setAVPlayerCallback(avPlayer: media.AVPlayer) {
    avPlayer.on('timeUpdate', (time: number) => {
      console.info(`AVPlayerDemo AVPlayer timeUpdate. time is ${time}`);
      this.currentTime = Math.floor(time * this.durationTime / avPlayer.duration);
      console.info(`AVPlayerDemo this.currentTime. time is ${this.currentTime}`);
      this.currentStringTime = this.secondToTime(Math.floor(time / 1000));
      if (this.currentAVSession) {
        this.playbackState.position = {
          elapsedTime: time, // 已经播放的位置,以ms为单位
          updateTime: (new Date()).getTime(), // 应用更新当前位置的时间戳,以ms为单位
        };
        this.currentAVSession.setAVPlaybackState(this.playbackState);
      }
    })

    // seek操作结果回调函数
    avPlayer.on('seekDone', (seekDoneTime: number) => {
      console.info(`AVPlayerDemo AVPlayer seekDone succeeded, seek time is ${seekDoneTime}`);
      if (this.currentAVSession) {
        this.playbackState.position = {
          elapsedTime: avPlayer.currentTime, // 已经播放的位置,以ms为单位
          updateTime: (new Date()).getTime(), // 应用更新当前位置的时间戳,以ms为单位
        };
        this.currentAVSession.setAVPlaybackState(this.playbackState);
      }
    })

    // 监听setSpeed生效的事件
    avPlayer.on('speedDone', (speed: number) => {
      console.info(`AVPlayerDemo AVPlayer speedDone succeeded, speed is ${speed}`);
      if (this.currentAVSession) {
        this.playbackState.speed = speed;
        this.currentAVSession.setAVPlaybackState(this.playbackState);
      }
    })

    // error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程
    avPlayer.on('error', (err: BusinessError) => {
      console.error(`AVPlayerDemo 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('AVPlayerDemo AVPlayer state idle called.');
          if (avPlayer && this.sourceFiles.length > this.currentIndex) {
            // 网络视频使用avPlayer.url赋值
            avPlayer.fdSrc = this.sourceFiles[this.currentIndex];
          }
          break;
        case 'initialized': // avplayer 设置播放源后触发该状态上报
          console.info('AVPlayerDemo AVPlayer state initialized called.');
          this.reset()
          if (this.isVideo) {
            avPlayer.surfaceId = this.surfaceID;
          }
          avPlayer.prepare();
          break;
        case 'prepared': // prepare调用成功后上报该状态机
          console.info('AVPlayerDemo AVPlayer state prepared called.');
          this.flag = true;
          this.durationTime = Math.floor(avPlayer.duration / 1000);
          this.durationStringTime = this.secondToTime(this.durationTime);
        // avPlayer.loop = true;
          avPlayer.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_1_00_X)
          avPlayer.seek(1, media.SeekMode.SEEK_PREV_SYNC)
          await this.startAVSession();
          break;
        case 'completed': // prepare调用成功后上报该状态机
          console.info('AVPlayerDemo AVPlayer state completed called.');
          this.isPlay = false;
          if (this.currentAVSession) {
            // 设置状态: 播放状态,进度位置,播放倍速,缓存的时间,资源的时长
            this.playbackState.state = avSession.PlaybackState.PLAYBACK_STATE_COMPLETED;
            this.currentAVSession.setAVPlaybackState(this.playbackState);
          }
          break;
        case 'playing': // play成功调用后触发该状态机上报
          console.info('AVPlayerDemo AVPlayer state playing called.');
          if (this.currentAVSession) {
            // 设置状态: 播放状态,进度位置,播放倍速,缓存的时间,资源的时长
            this.playbackState.state = avSession.PlaybackState.PLAYBACK_STATE_PLAY;
            this.currentAVSession.setAVPlaybackState(this.playbackState);
          }
          break;
        case 'paused': // pause成功调用后触发该状态机上报
          console.info('AVPlayerDemo AVPlayer state paused called.');
          if (this.currentAVSession) {
            // 设置状态: 播放状态,进度位置,播放倍速,缓存的时间,资源的时长
            this.playbackState.state = avSession.PlaybackState.PLAYBACK_STATE_PAUSE;
            this.playbackState.position = {
              elapsedTime: avPlayer.currentTime, // 已经播放的位置,以ms为单位
              updateTime: (new Date()).getTime(), // 应用更新当前位置的时间戳,以ms为单位
            };
            this.currentAVSession.setAVPlaybackState(this.playbackState);
          }
          break;
        case 'stopped': // stop接口成功调用后触发该状态机上报
          console.info('AVPlayerDemo AVPlayer state stopped called.');
          if (this.currentAVSession) {
            // 设置状态: 播放状态,进度位置,播放倍速,缓存的时间,资源的时长
            this.playbackState.state = avSession.PlaybackState.PLAYBACK_STATE_STOP;
            this.currentAVSession.setAVPlaybackState(this.playbackState);
          }
          break;
        case 'released':
          console.info('AVPlayerDemo AVPlayer state released called.');
          break;
        default:
          console.info('AVPlayerDemo AVPlayer state unknown called.');
          break;
      }
    })
  }

  startContinuousTask() {
    let wantAgentInfo: wantAgent.WantAgentInfo = {
      // 点击通知后,将要执行的动作列表
      // 添加需要被拉起应用的bundleName和abilityName
      wants: [
        {
          bundleName: "com.xxx.xxx",
          abilityName: "EntryAbility"
        }
      ],
      // 指定点击通知栏消息后的动作是拉起ability
      actionType: wantAgent.OperationType.START_ABILITY,
      // 使用者自定义的一个私有值
      requestCode: 0,
      // 点击通知后,动作执行属性
      actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
    };

    // 通过wantAgent模块下getWantAgent方法获取WantAgent对象
    wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
      backgroundTaskManager.startBackgroundRunning(getContext(this),
        backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, wantAgentObj).then(() => {
        console.info(`AVPlayerDemo Succeeded in operationing startBackgroundRunning.`);
      }).catch((err: BusinessError) => {
        console.error(`AVPlayerDemo Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
      });
    });
  }

  stopContinuousTask() {
    backgroundTaskManager.stopBackgroundRunning(getContext(this)).then(() => {
      console.info(`AVPlayerDemo Succeeded in operationing stopBackgroundRunning.`);
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
    });
  }

  reset(sourceFlag?: boolean) {
    this.isPlay = false;
    this.currentTime = 0;
    this.durationTime = 0;
    this.durationStringTime = '00:00';
    this.currentStringTime = '00:00';
    this.flag = false;
    if (sourceFlag) {
      this.currentIndex = 0;
      this.isFullScreen = false;
      if (this.isVideo) {
        this.sourceFiles = this.videoFiles;
      } else {
        this.sourceFiles = this.audioFiles;
      }
      if (this.avPlayer) {
        this.avPlayer.reset()
      }
    }

    if (this.pipController) {
      this.pipController.stopPiP();
    }
  }

  setSpeed(playSpeed: number) {
    if (!this.avPlayer || this.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) {
      console.error('AVPlayerDemo setSpeed failed. no avPlayer or state is not prepared/playing/paused/completed')
      return;
    }
    this.avPlayer.setSpeed(playSpeed);
  }

  async play() {
    if (!this.avPlayer || this.OPERATE_STATE.indexOf(this.avPlayer.state) === -1 ||
      this.OPERATE_STATE.indexOf(this.avPlayer.state) === 1) {
      console.error('AVPlayerDemo play failed. no avPlayer or state is not prepared/paused/completed')
      return;
    }
    this.isPlay = true;
    if (this.avPlayer.state === 'completed') {
      this.currentTime = 0
      this.currentStringTime = '00:00'
      this.avPlayer.seek(1, media.SeekMode.SEEK_PREV_SYNC);
    }
    this.avPlayer.play();
  }

  async startAVSession() {
    if (!this.currentAVSession) {
      console.error('AVPlayerDemo currentAVSession is undefined.')
      return;
    }
    let metadata: avSession.AVMetadata = this.generateAVMetadata();
    await this.currentAVSession.setAVMetadata(metadata).then(() => {
      console.info(`AVPlayerDemo SetAVMetadata successfully`);
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo SetAVMetadata BusinessError: code: ${err.code}, message: ${err.message}`);
    });
    this.playbackState.state = avSession.PlaybackState.PLAYBACK_STATE_PREPARE;
    this.playbackState.duration = this.avPlayer?.duration;
    this.currentAVSession.setAVPlaybackState(this.playbackState);
    // 通过按钮申请长时任务
    this.startContinuousTask();
    this.currentAVSession.getController().then((avcontroller: avSession.AVSessionController) => {
      this.avsessionController = avcontroller;
      console.info(`AVPlayerDemo GetController : SUCCESS : sessionid : ${avcontroller.sessionId}`);
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo GetController BusinessError: code: ${err.code}, message: ${err.message}`);
    });
    await this.currentAVSession.activate().then(() => {
      console.info(`AVPlayerDemo Activate : SUCCESS `);
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo Activate BusinessError: code: ${err.code}, message: ${err.message}`);
    });
  }

  private generateAVMetadata() {
    let previousIndex = this.addStepIndex(-1);
    let nextIndex = this.addStepIndex(1);
    let metadata: avSession.AVMetadata = {
      assetId: `${this.sourceFiles[this.currentIndex].fd}`, // 必须,媒体ID。歌曲的唯一标识,由应用自定义。
      title: `${this.sourceFiles[this.currentIndex].fd}`, // 标题
      artist: `艺术家${this.currentIndex}`, // 艺术家
      author: `专辑作者${this.currentIndex}`, // 专辑作者
      // avQueueId: "", // 歌单(歌曲列表)唯一标识Id
      // avQueueImage: "", // 歌单(歌曲列表)封面图,图片的像素数据或者图片路径地址(本地路径或网络路径)
      album: `专辑名称${this.currentIndex}`, // 专辑名称
      writer: `词作者${this.currentIndex}`, // 词作者
      composer: `作曲者${this.currentIndex}`, // 作曲者
      duration: this.avPlayer?.duration, // 媒体时长,单位毫秒(ms)
      mediaImage: this.curPixelMap, // 图片的像素数据或者图片路径地址(本地路径或网络路径)
      publishDate: new Date(), // 发行日期
      subtitle: `子标题${this.currentIndex}`, // 子标题
      description: `媒体描述${this.currentIndex}`, // 媒体描述
      // lyric: "xxxxx", // 歌词文件路径地址(本地路径或网络路径),当前仅支持本地文件
      previousAssetId: `${this.sourceFiles[previousIndex].fd}`, // 上一首媒体ID
      nextAssetId: `${this.sourceFiles[nextIndex].fd}`, // 下一首媒体ID
    };
    return metadata;
  }

  async createAVSession() {
    let type: avSession.AVSessionType = this.isVideo ? 'video' : 'audio';
    await avSession.createAVSession(getContext(this), 'AVPlayerDemo', type).then((data: avSession.AVSession) => {
      console.info(`AVPlayerDemo CreateAVSession : SUCCESS : sessionId = ${data.sessionId}`);
      this.currentAVSession = data;
      this.curSessionId = data.sessionId;
      this.setAVSessionCallback(data);
    }).catch((err: BusinessError) => {
      console.error(`AVPlayerDemo CreateAVSession BusinessError: code: ${err.code}, message: ${err.message}`);
    });
  }

  setAVSessionCallback(curAvSession: avSession.AVSession) {
    // 播放
    curAvSession.on('play', () => {
      console.info(`AVPlayerDemo AVSession on play entry`);
      this.play();
    });
    // 暂停
    curAvSession.on('pause', () => {
      console.info(`AVPlayerDemo AVSession on pause entry`);
      this.isPlay = false;
      if (this.avPlayer) {
        this.avPlayer.pause();
      }
    });
    // 停止
    curAvSession.on('stop', () => {
      console.info(`AVPlayerDemo AVSession on stop entry`);
      this.stopPlay();
    });
    // 下一个
    curAvSession.on('playNext', () => {
      console.info(`AVPlayerDemo AVSession on playNext entry`);
      this.goToNextOrPre(1);
    });
    // 上一个
    curAvSession.on('playPrevious', () => {
      console.info(`AVPlayerDemo AVSession on playPrevious entry`);
      this.goToNextOrPre(-1);
    });
    // 快进
    curAvSession.on('fastForward', () => {
      console.info(`AVPlayerDemo AVSession on fastForward entry`);
      this.setSeek(15);
    });
    // 快退
    curAvSession.on('rewind', () => {
      console.info(`AVPlayerDemo AVSession on rewind entry`);
      this.setSeek(-15);
    });
    // 媒体id播放监听事件
    curAvSession.on('playFromAssetId', (assetId: number) => {
      console.info(`AVPlayerDemo AVSession on playFromAssetId entry assetId : ${assetId}`);
    });
    // 跳转节点监听事件
    curAvSession.on('seek', (time: number) => {
      console.info(`AVPlayerDemo AVSession on seek entry time : ${time}`);
      this.setSeek(time);
    });
    // 播放速率的监听事件
    curAvSession.on('setSpeed', (speed: number) => {
      console.info(`AVPlayerDemo AVSession on setSpeed entry speed : ${speed}`);
      this.setSpeed(speed);
    });
  }

  async saveRawFileToPixelMap(rawFilePath: string) {
    let value: Uint8Array = await getContext(this).resourceManager.getRawFileContent(rawFilePath);
    let imageBuffer: ArrayBuffer = value.buffer as ArrayBuffer;
    let imageSource: image.ImageSource = image.createImageSource(imageBuffer);
    await imageSource.createPixelMap({ desiredSize: { width: 900, height: 900 } }).then((pixelMap: image.PixelMap) => {
      console.info('AVPlayerDemo Succeeded in creating pixelMap object through image decoding parameters.');
      this.curPixelMap = pixelMap;
    }).catch((error: BusinessError) => {
      console.error('AVPlayerDemo Failed to create pixelMap object through image decoding parameters.');
    })
  }

  private addStepIndex(num: number): number {
    let result = this.currentIndex + num;
    if (result < 0) {
      result = this.sourceFiles.length - 1;
    } else if (result > this.sourceFiles.length - 1) {
      result = 0;
    }
    return result;
  }

  iconOnclick() {
    if (this.isPlay === true) {
      this.avPlayer && this.avPlayer.pause();
      this.isPlay = false;
      this.isOpacity = false;
      return;
    }
    if (this.flag === true) {
      this.avPlayer && this.avPlayer.play();
      this.isPlay = true;
      this.isOpacity = true;
    } else {
      // The scheduled task determines whether the video loading is complete.
      let intervalFlag = setInterval(() => {
        if (this.flag === true) {
          this.avPlayer && this.avPlayer.play();
          this.isPlay = true;
          this.isOpacity = true;
          clearInterval(intervalFlag);
        }
      }, 100);
    }
  }

  sliderOnchange(value: number, mode: SliderChangeMode) {
    console.info(`AVPlayerDemo sliderOnchange. value is ${value}`);
    if (!this.avPlayer) {
      return;
    }
    this.currentTime = value
    if (mode === SliderChangeMode.Begin || mode === SliderChangeMode.Moving) {
      this.isOpacity = false;
    }
    if (mode === SliderChangeMode.End && this.avPlayer) {
      let seekTime: number = value * this.avPlayer.duration / this.durationTime;
      this.currentStringTime = this.secondToTime(Math.floor(seekTime / 1000));
      console.info(`AVPlayerDemo sliderOnchange. time is ${seekTime}, currentTime is ${this.currentTime}`);
      this.avPlayer.seek(seekTime, media.SeekMode.SEEK_PREV_SYNC);
      this.isOpacity = true;
    }
  }

  /**
   * Seconds converted to HH:mm:ss.
   *
   * @param seconds Maximum video duration (seconds).
   * @return Time after conversion.
   */
  secondToTime(seconds: number): string {
    let hourUnit = 60 * 60;
    let hour: number = Math.floor(seconds / hourUnit);
    let minute: number = Math.floor((seconds - hour * hourUnit) / 60);
    let second: number = seconds - hour * hourUnit - minute * 60;
    let hourStr: string = hour < 10 ? `0${hour.toString()}` : `${hour.toString()}`
    let minuteStr: string = minute < 10 ? `0${minute.toString()}` : `${minute.toString()}`
    let secondStr: string = second < 10 ? `0${second.toString()}` : `${second.toString()}`
    if (hour > 0) {
      return `${hourStr}:${minuteStr}:${secondStr}`;
    }
    if (minute > 0) {
      return `${minuteStr}:${secondStr}`;
    } else {
      return `00:${secondStr}`;
    }
  }

  playOrPause() {
    if (this.avPlayer) {
      if (this.isPlay) {
        this.isPlay = false;
        this.avPlayer.pause();
      } else {
        this.play();
      }
    }
  }

  createAVPlayer() {
    media.createAVPlayer().then((video: media.AVPlayer) => {
      if (video != null) {
        this.avPlayer = video;
        this.setAVPlayerCallback(this.avPlayer);
        if (this.avPlayer && this.sourceFiles.length > this.currentIndex) {
          this.avPlayer.fdSrc = this.sourceFiles[this.currentIndex];
        }
        console.info('AVPlayerDemo createAVPlayer success');
      } else {
        console.error('AVPlayerDemo createAVPlayer fail');
      }
    }).catch((error: BusinessError) => {
      console.error(`AVPlayerDemo AVPlayer catchCallback, error message:${error.message}`);
    });
  }

  initFiles() {
    let fileList: string[] = getContext(this).resourceManager.getRawFileListSync('video');
    fileList.forEach((fileStr: string) => {
      // 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址
      // 返回类型为{fd,offset,length},fd为HAP包fd地址,offset为媒体资源偏移量,length为播放长度
      let fileDescriptor = getContext().resourceManager.getRawFdSync(`video/${fileStr}`);
      let avFileDescriptor: media.AVFileDescriptor = {
        fd: fileDescriptor.fd,
        offset: fileDescriptor.offset,
        length: fileDescriptor.length
      };
      this.videoFiles.push(avFileDescriptor)
    })

    let fileList2: string[] = getContext(this).resourceManager.getRawFileListSync('audio');
    fileList2.forEach((fileStr: string) => {
      // 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址
      // 返回类型为{fd,offset,length},fd为HAP包fd地址,offset为媒体资源偏移量,length为播放长度
      let fileDescriptor = getContext().resourceManager.getRawFdSync(`audio/${fileStr}`);
      let avFileDescriptor: media.AVFileDescriptor = {
        fd: fileDescriptor.fd,
        offset: fileDescriptor.offset,
        length: fileDescriptor.length
      };
      this.audioFiles.push(avFileDescriptor)
    })

    if (this.isVideo) {
      this.sourceFiles = this.videoFiles;
    } else {
      this.sourceFiles = this.audioFiles;
    }
  }

  setSeek(addSecond: number, curTime?: number) {
    if (!this.avPlayer || this.OPERATE_STATE.indexOf(this.avPlayer.state) === -1) {
      console.error('AVPlayerDemo setSeek failed. no avPlayer or state is not prepared/playing/paused/completed')
      return;
    }
    if (!curTime) {
      curTime = this.avPlayer.currentTime;
    }
    let curMillSeconds: number = curTime + addSecond * 1000;
    curMillSeconds = Math.min(Math.max(curMillSeconds, 0), this.avPlayer.duration);

    this.currentTime = curMillSeconds * this.durationTime / this.avPlayer.duration;
    this.currentStringTime = this.secondToTime(Math.floor(curMillSeconds / 1000));
    console.error(`AVPlayerDemo setSeek. curMillSeconds is ${curMillSeconds}`)
    this.avPlayer.seek(curMillSeconds, media.SeekMode.SEEK_PREV_SYNC);
  }

  goToNextOrPre(num: number) {
    this.currentIndex += num;
    if (this.currentIndex < 0) {
      this.currentIndex = this.sourceFiles.length - 1;
    } else if (this.currentIndex > this.sourceFiles.length - 1) {
      this.currentIndex = 0;
    }
    if (this.avPlayer) {
      this.avPlayer.reset();
    }
    console.info(`AVPlayerDemo goToNextOrPre success. currentIndex is ${this.currentIndex}`)
  }

  stopPlay() {
    if (this.avPlayer) {
      this.avPlayer.stop();
      this.reset();
      this.avPlayer.reset();
      this.avPlayer.seek(1, media.SeekMode.SEEK_NEXT_SYNC);
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
  • 269.
  • 270.
  • 271.
  • 272.
  • 273.
  • 274.
  • 275.
  • 276.
  • 277.
  • 278.
  • 279.
  • 280.
  • 281.
  • 282.
  • 283.
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.
  • 294.
  • 295.
  • 296.
  • 297.
  • 298.
  • 299.
  • 300.
  • 301.
  • 302.
  • 303.
  • 304.
  • 305.
  • 306.
  • 307.
  • 308.
  • 309.
  • 310.
  • 311.
  • 312.
  • 313.
  • 314.
  • 315.
  • 316.
  • 317.
  • 318.
  • 319.
  • 320.
  • 321.
  • 322.
  • 323.
  • 324.
  • 325.
  • 326.
  • 327.
  • 328.
  • 329.
  • 330.
  • 331.
  • 332.
  • 333.
  • 334.
  • 335.
  • 336.
  • 337.
  • 338.
  • 339.
  • 340.
  • 341.
  • 342.
  • 343.
  • 344.
  • 345.
  • 346.
  • 347.
  • 348.
  • 349.
  • 350.
  • 351.
  • 352.
  • 353.
  • 354.
  • 355.
  • 356.
  • 357.
  • 358.
  • 359.
  • 360.
  • 361.
  • 362.
  • 363.
  • 364.
  • 365.
  • 366.
  • 367.
  • 368.
  • 369.
  • 370.
  • 371.
  • 372.
  • 373.
  • 374.
  • 375.
  • 376.
  • 377.
  • 378.
  • 379.
  • 380.
  • 381.
  • 382.
  • 383.
  • 384.
  • 385.
  • 386.
  • 387.
  • 388.
  • 389.
  • 390.
  • 391.
  • 392.
  • 393.
  • 394.
  • 395.
  • 396.
  • 397.
  • 398.
  • 399.
  • 400.
  • 401.
  • 402.
  • 403.
  • 404.
  • 405.
  • 406.
  • 407.
  • 408.
  • 409.
  • 410.
  • 411.
  • 412.
  • 413.
  • 414.
  • 415.
  • 416.
  • 417.
  • 418.
  • 419.
  • 420.
  • 421.
  • 422.
  • 423.
  • 424.
  • 425.
  • 426.
  • 427.
  • 428.
  • 429.
  • 430.
  • 431.
  • 432.
  • 433.
  • 434.
  • 435.
  • 436.
  • 437.
  • 438.
  • 439.
  • 440.
  • 441.
  • 442.
  • 443.
  • 444.
  • 445.
  • 446.
  • 447.
  • 448.
  • 449.
  • 450.
  • 451.
  • 452.
  • 453.
  • 454.
  • 455.
  • 456.
  • 457.
  • 458.
  • 459.
  • 460.
  • 461.
  • 462.
  • 463.
  • 464.
  • 465.
  • 466.
  • 467.
  • 468.
  • 469.
  • 470.
  • 471.
  • 472.
  • 473.
  • 474.
  • 475.
  • 476.
  • 477.
  • 478.
  • 479.
  • 480.
  • 481.
  • 482.
  • 483.
  • 484.
  • 485.
  • 486.
  • 487.
  • 488.
  • 489.
  • 490.
  • 491.
  • 492.
  • 493.
  • 494.
  • 495.
  • 496.
  • 497.
  • 498.
  • 499.
  • 500.
  • 501.
  • 502.
  • 503.
  • 504.
  • 505.
  • 506.
  • 507.
  • 508.
  • 509.
  • 510.
  • 511.
  • 512.
  • 513.
  • 514.
  • 515.
  • 516.
  • 517.
  • 518.
  • 519.
  • 520.
  • 521.
  • 522.
  • 523.
  • 524.
  • 525.
  • 526.
  • 527.
  • 528.
  • 529.
  • 530.
  • 531.
  • 532.
  • 533.
  • 534.
  • 535.
  • 536.
  • 537.
  • 538.
  • 539.
  • 540.
  • 541.
  • 542.
  • 543.
  • 544.
  • 545.
  • 546.
  • 547.
  • 548.
  • 549.
  • 550.
  • 551.
  • 552.
  • 553.
  • 554.
  • 555.
  • 556.
  • 557.
  • 558.
  • 559.
  • 560.
  • 561.
  • 562.
  • 563.
  • 564.
  • 565.
  • 566.
  • 567.
  • 568.
  • 569.
  • 570.
  • 571.
  • 572.
  • 573.
  • 574.
  • 575.
  • 576.
  • 577.
  • 578.
  • 579.
  • 580.
  • 581.
  • 582.
  • 583.
  • 584.
  • 585.
  • 586.
  • 587.
  • 588.
  • 589.
  • 590.
  • 591.
  • 592.
  • 593.
  • 594.
  • 595.
  • 596.
  • 597.
  • 598.
  • 599.
  • 600.
  • 601.
  • 602.
  • 603.
  • 604.
  • 605.
  • 606.
  • 607.
  • 608.
  • 609.
  • 610.
  • 611.
  • 612.
  • 613.
  • 614.
  • 615.
  • 616.
  • 617.
  • 618.
  • 619.
  • 620.
  • 621.
  • 622.
  • 623.
  • 624.
  • 625.
  • 626.
  • 627.
  • 628.
  • 629.
  • 630.
  • 631.
  • 632.
  • 633.
  • 634.
  • 635.
  • 636.
  • 637.
  • 638.
  • 639.
  • 640.
  • 641.
  • 642.
  • 643.
  • 644.
  • 645.
  • 646.
  • 647.
  • 648.
  • 649.
  • 650.
  • 651.
  • 652.
  • 653.
  • 654.
  • 655.
  • 656.
  • 657.
  • 658.
  • 659.
  • 660.
  • 661.
  • 662.
  • 663.
  • 664.
  • 665.
  • 666.
  • 667.
  • 668.
  • 669.
  • 670.
  • 671.
  • 672.
  • 673.
  • 674.
  • 675.
  • 676.
  • 677.
  • 678.
  • 679.
  • 680.
  • 681.
  • 682.
  • 683.
  • 684.
  • 685.
  • 686.
  • 687.
  • 688.
  • 689.
  • 690.
  • 691.
  • 692.
  • 693.
  • 694.
  • 695.
  • 696.
  • 697.
  • 698.
  • 699.
  • 700.
  • 701.
  • 702.
  • 703.
  • 704.
  • 705.
  • 706.
  • 707.
  • 708.
  • 709.
  • 710.
  • 711.
  • 712.
  • 713.
  • 714.
  • 715.
  • 716.
  • 717.
  • 718.
  • 719.
  • 720.
  • 721.
  • 722.
  • 723.
  • 724.
  • 725.
  • 726.
  • 727.
  • 728.
  • 729.
  • 730.
  • 731.
  • 732.
  • 733.
  • 734.
  • 735.
  • 736.
  • 737.
  • 738.
  • 739.
  • 740.
  • 741.
  • 742.
  • 743.
  • 744.
  • 745.
  • 746.
  • 747.
  • 748.
  • 749.
  • 750.
  • 751.
  • 752.
  • 753.
  • 754.
  • 755.
  • 756.
  • 757.
  • 758.
  • 759.
  • 760.
  • 761.
  • 762.
  • 763.
  • 764.
  • 765.
  • 766.
  • 767.
  • 768.
  • 769.
  • 770.
  • 771.
  • 772.
  • 773.
  • 774.
  • 775.
  • 776.
  • 777.
  • 778.
  • 779.
  • 780.
  • 781.
  • 782.
  • 783.
  • 784.
  • 785.
  • 786.
  • 787.
  • 788.
  • 789.
  • 790.
  • 791.
  • 792.
  • 793.
  • 794.
  • 795.
  • 796.
  • 797.
  • 798.
  • 799.
  • 800.
  • 801.
  • 802.
  • 803.
  • 804.
  • 805.
  • 806.
  • 807.
  • 808.
  • 809.
  • 810.
  • 811.
  • 812.
  • 813.
  • 814.
  • 815.
  • 816.
  • 817.
  • 818.
  • 819.
  • 820.
  • 821.
  • 822.
  • 823.
  • 824.
  • 825.
  • 826.
  • 827.
  • 828.
  • 829.
  • 830.
  • 831.
  • 832.
  • 833.
  • 834.
  • 835.
  • 836.
  • 837.
  • 838.
  • 839.
  • 840.
  • 841.
  • 842.
  • 843.
  • 844.
  • 845.
  • 846.
  • 847.
  • 848.
  • 849.
  • 850.
  • 851.
  • 852.
  • 853.
  • 854.
  • 855.
  • 856.
  • 857.
  • 858.
  • 859.
  • 860.
  • 861.
  • 862.
  • 863.
  • 864.
  • 865.
  • 866.
  • 867.
  • 868.
  • 869.
  • 870.
  • 871.
  • 872.
  • 873.
  • 874.
  • 875.
  • 876.
  • 877.
  • 878.
  • 879.
  • 880.
  • 881.
  • 882.
  • 883.
  • 884.
  • 885.
  • 886.
  • 887.
  • 888.
  • 889.
  • 890.
  • 891.
  • 892.
  • 893.
  • 894.
  • 895.
  • 896.
  • 897.
  • 898.
  • 899.
  • 900.
  • 901.
  • 902.
  • 903.
  • 904.
  • 905.
  • 906.
  • 907.
  • 908.
  • 909.
  • 910.
  • 911.
  • 912.
  • 913.
  • 914.
  • 915.
  • 916.
  • 917.
  • 918.
  • 919.
  • 920.
  • 921.
  • 922.
  • 923.
  • 924.
  • 925.
  • 926.
  • 927.
  • 928.
  • 929.
  • 930.
  • 931.
  • 932.
  • 933.
  • 934.
  • 935.
  • 936.
  • 937.
  • 938.
  • 939.
  • 940.
  • 941.
  • 942.
  • 943.
  • 944.
  • 945.
  • 946.
  • 947.
  • 948.
  • 949.
  • 950.
  • 951.
  • 952.
  • 953.
  • 954.
  • 955.
  • 956.
  • 957.
  • 958.
  • 959.
  • 960.
  • 961.
  • 962.
  • 963.
  • 964.
  • 965.
  • 966.
  • 967.
  • 968.
  • 969.
  • 970.
  • 971.
  • 972.
  • 973.
  • 974.
  • 975.
  • 976.
  • 977.
  • 978.
  • 979.
  • 980.
  • 981.
  • 982.
  • 983.
  • 984.
  • 985.
  • 986.
  • 987.
  • 988.
  • 989.
  • 990.
  • 991.
  • 992.
  • 993.
  • 994.
  • 995.
  • 996.
  • 997.
  • 998.
  • 999.
  • 1000.
  • 1001.
  • 1002.
  • 1003.
  • 1004.
  • 1005.
  • 1006.
  • 1007.
  • 1008.
  • 1009.
  • 1010.
  • 1011.
  • 1012.
  • 1013.
  • 1014.
  • 1015.
  • 1016.
  • 1017.
  • 1018.
  • 1019.
  • 1020.
  • 1021.
  • 1022.
  • 1023.
  • 1024.
  • 1025.
  • 1026.

2、index.ets

import media from '@ohos.multimedia.media';
import common from '@ohos.app.ability.common';
import fs from '@ohos.file.fs';
import request from '@ohos.request';
import { BusinessError } from '@ohos.base';
import buffer from '@ohos.buffer';


let context = getContext(this) as common.UIAbilityContext;
// 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例
let pathDir = context.filesDir;
let path = pathDir + '/1234.mp4';

@Entry
@Component
struct AVPlayerDemo {
  xComponentController: XComponentController = new XComponentController();
  surfaceID: string = '';
  public xComponentContext: Record<string, () => void> = {}
  public player: media.AVPlayer | null = null;
  private fileSize: number = -1;
  private fd: number = 0;
  public isSeek: boolean = true;

  build() {
    Column() {
      XComponent({
        id: 'AVPlayer',
        type: XComponentType.SURFACE,
        controller: this.xComponentController
      })
        .onLoad(() => {
          this.surfaceID = this.xComponentController.getXComponentSurfaceId()
          this.xComponentContext = this.xComponentController.getXComponentContext() as Record<string, () => void>
          this.read();
        })

      Button('speed')
        .onClick(() => {
          this.player?.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X);
        })
        .margin({ right: 12 })
        .margin({ top: 10 })
        .width(150)

      Button('paused')
        .onClick(() => {
          this.player?.pause();
        })
        .margin({ right: 12 })
        .margin({ top: 20 })
        .width(150)

      Button('seek')
        .onClick(() => {
          this.player?.seek(9000, 0);
        })
        .margin({ right: 12 })
        .margin({ top: 20 })
        .width(150)

      Button('player')
        .onClick(() => {
          this.avPlayerDataSrcNOSeekDemo()
        })
        .margin({ right: 12 })
        .margin({ top: 20 })
        .width(150)

      Button('reset')
        .onClick(() => {
          this.player?.reset();
        })
        .margin({ right: 12 })
        .margin({ top: 20 })
        .width(150)
    }
    .margin({ top: 40 })
    .height(400)
  }

  async avPlayerDataSrcNOSeekDemo() {
    // 创建avPlayer实例对象
    this.player = await media.createAVPlayer();
    // 创建状态机变化回调函数
    this.setAVPlayerCallback(this.player);
    // dataSrc播放模式的的播放源地址,当播放为Seek模式时fileSize为播放文件的具体大小,下面会对fileSize赋值
    let src: media.AVDataSrcDescriptor = {
      fileSize: -1,
      callback: (buf: ArrayBuffer, length: number) => {
        let num = 0;
        if (buf == undefined || length == undefined) {
          return -1;
        }
        num = fs.readSync(this.fd, buf);
        if (num > 0) {
          return num;
        }
        return -1;
      }
    }
    let context = getContext(this) as common.UIAbilityContext;
    // 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例
    let pathDir = context.filesDir;
    let path = pathDir + '/1234.mp4';
    await fs.open(path).then((file: fs.File) => {
      this.fd = file.fd;
    })
    // 获取播放文件的大小
    this.fileSize = fs.statSync(path).size;
    src.fileSize = this.fileSize;
    this.isSeek = false; // 支持seek操作
    this.player.dataSrc = src;
  }

  async read() {
    let context = getContext(this) as common.UIAbilityContext;
    let filesDir = context.filesDir;
    console.info(filesDir)
    request.downloadFile(context, {
      url: 'xxx.mp4',
      filePath: filesDir + '/1234.mp4'
    }).then((downloadTask: request.DownloadTask) => {
      downloadTask.on('complete', () => {
        let file = fs.openSync(filesDir + '/1234.mp4', fs.OpenMode.READ_WRITE);
        let arrayBuffer = new ArrayBuffer(1024);
        let readLen = fs.readSync(file.fd, arrayBuffer);
        let buf = buffer.from(arrayBuffer, 0, readLen);
        console.info(`The content of file: ${buf.toString()}`);
        console.info(filesDir)
        fs.closeSync(file);
      })
    }).catch((err: BusinessError) => {
      console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
    });
  }

  // 注册avplayer回调函数
  private setAVPlayerCallback(avPlayer: media.AVPlayer) {
    if (this.player == null) {
      return;
    }
    // // 响应API调用,监听seek()请求完成情况。
    avPlayer.on('speedDone', (number: Number) => this.speedDone(number));
    avPlayer.on('seekDone', (number: Number) => this.seekDone(number));

    // 状态机变化回调函数
    avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
      switch (state) {
        case 'idle': // 成功调用reset接口后触发该状态机上报
          console.info('AVPlayer state idle called.');
          this.avPlayerDataSrcNOSeekDemo()
        //avPlayer.release(); // 调用release接口销毁实例对象
          break;
        case 'initialized': // avplayer 设置播放源后触发该状态上报
          console.info('AVPlayer state initialized called.');
          avPlayer.surfaceId = this.surfaceID; // 设置显示画面,当播放的资源为纯音频时无需设置
          avPlayer.prepare();
          break;
        case 'prepared': // prepare调用成功后上报该状态机
          console.info('AVPlayer state prepared called.');
          avPlayer.play(); // 调用播放接口开始播放
          break;
        case 'playing': // play成功调用后触发该状态机上报
          console.info('AVPlayer state playing called.');
          break;
        case 'paused': // pause成功调用后触发该状态机上报
          console.info('AVPlayer state paused called.');
          break;
        case 'completed': // 播放结束后触发该状态机上报
          console.info('AVPlayer state completed called.');
          avPlayer.stop(); //调用播放结束接口
          break;
        case 'stopped': // stop接口成功调用后触发该状态机上报
          console.info('AVPlayer state stopped called.');
          avPlayer.release(); // 调用reset接口初始化avplayer状态
          break;
        case 'released':
          console.info('AVPlayer state released called.');
          fs.unlink(path)
          break;
        default:
          console.info('AVPlayer state unknown called.');
          break;
      }
    })
  }

  private speedDone(number: Number) {
    console.info('AVPlayer

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
分享
微博
QQ
微信
回复
2024-12-25 15:28:34
相关问题
HarmonyOS VideoController无法继承
722浏览 • 1回复 待解决
HarmonyOS @Reusable缺少API文档
983浏览 • 1回复 待解决
HarmonyOS 手机缺少方正字体
635浏览 • 1回复 待解决
缺少serialport包,终端重用
4291浏览 • 1回复 待解决
HarmonyOS waterflow组件卡片删除缺少动画
1012浏览 • 1回复 待解决
HarmonyOS base64解码内容缺少
634浏览 • 1回复 待解决
关于权限列表条目缺少问题
2734浏览 • 1回复 待解决
HarmonyOS react-native-fs依赖缺少cpp文件
583浏览 • 1回复 待解决
HarmonyOS Push Kit 缺少服务端sdk的demo
934浏览 • 1回复 待解决
崩溃信息中缺少详细的系统信息
1459浏览 • 1回复 待解决
DevEco-studio提示缺少zipalign怎么回事?
3492浏览 • 1回复 待解决