HarmonyOS video 视频播放器

源码

import { display, window } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  controller: VideoController = new VideoController() //video控制器
  @State curRate: PlaybackSpeed = PlaybackSpeed.Speed_Forward_1_00_X; //播放倍数
  @State curRateName: number = 1; //设置默认播放倍数 用于页面展示文字内容
  @State isAutoPlay: boolean = true //自动播放
  @State isStart: boolean = false //播放状态 开始
  @State showControls: boolean = false//是否展示video自带控件
  @State videoSrc: Resource = $rawfile('video1.mp4') //默认视频路径
  @State previewUri: Resource = $r('app.media.poster1') //默认视频播放预览图片
  @State videoIndex: number = 0; //当前播放视频索引
  @State isFullscreen: boolean = false //是否全屏状态
  // 视频信息列表
  @State VideoList: Array<videoInfo> = [
    new videoInfo($rawfile('video1.mp4'), $r('app.media.poster1')),
    new videoInfo($rawfile('video2.mp4'), $r('app.media.poster2')),
    new videoInfo($rawfile('video3.mp4'), $r('app.media.poster3')),
    new videoInfo($rawfile('video4.mp4'), $r('app.media.poster4'))
  ]
  // 播放倍数list
  @State PlaybackSpeedList: Array<backSpeedInfo> = [
    new backSpeedInfo(0.75, PlaybackSpeed.Speed_Forward_0_75_X),
    new backSpeedInfo(1, PlaybackSpeed.Speed_Forward_1_00_X),
    new backSpeedInfo(1.25, PlaybackSpeed.Speed_Forward_1_25_X),
    new backSpeedInfo(1.75, PlaybackSpeed.Speed_Forward_1_75_X),
    new backSpeedInfo(2, PlaybackSpeed.Speed_Forward_2_00_X)
  ]
  // 获取主窗口实例
  windowStage: window.WindowStage = AppStorage.get('windowStage') as window.WindowStage;
  // 获取主窗口的方式
  mainWin: window.Window = this.windowStage.getMainWindowSync();

  @State videoHeight: string = '27%' //video高度  ,竖屏
  @State isSHowCurRateList: boolean = false //是否显示播放倍数列表
  @State isMute: boolean = false //静音
  @State videoDuration: string = '0' //video总时长
  @State totalTime: number = 0 //进度条总时长
  @State videoDurationEnd: string = '00:00' //进度条倒计时
  @State ProgressTotal: number = 0 //进度条value转换使用的video总时长
  @State ProgressValue: number = 0 //进度条完成进度
  @State ProgressValueFormat: number = 0//进度条完成进度value转换使用的进度条完成
  @State isLandSpace: boolean = false //是否横屏状态 用于设置vide及控件宽度
  @State isShowVideoControls: boolean = false //是否显示自定义控件


  //设置横屏、竖屏
  setWindowFullscreen() {
    // 获取最上层窗口的方式
    window.getLastWindow(getContext(this));
    if (this.isFullscreen) {
      this.videoHeight = '100%'
      //横屏
      this.mainWin.setPreferredOrientation(window.Orientation.LANDSCAPE);
      this.isLandSpace = true
    } else {
      this.videoHeight = '27%'
      //竖屏
      this.mainWin.setPreferredOrientation(window.Orientation.PORTRAIT);
      this.isLandSpace = false
    }
    // 使用display接口获取当前旋转方向,可以放置在监听中持续获取
    display.getDefaultDisplaySync().rotation;
  }

  //点击上下按钮时获取video信息
  getVideo(type: string) {
    this.isStart = false
    this.controller.stop()

    if (type === 'left') {
      this.videoIndex--
    } else {
      this.videoIndex++
    }

    this.VideoList.forEach((item: videoInfo, index) => {
      if (this.videoIndex === index) {
        this.videoSrc = item.videoSrc
        this.previewUri = item.previewUri
      }
    })
    this.isAutoPlay = true
    this.isStart = true
  }

  //计算时间
  getDuration(Time: number) {
    let seconds = Time;
    let hours = Math.floor(seconds / 3600);
    let minutes = Math.floor((seconds % 3600) / 60);
    let remainingSeconds = seconds % 60;

    let hour = hours === 0 ? '' : hours > 9 ? hours : '0' + hours
    let min = minutes === 0 ? '00' : minutes > 9 ? minutes : '0' + minutes
    let seco = remainingSeconds === 0 ? '00' : remainingSeconds > 9 ? remainingSeconds : '0' + remainingSeconds
    let time = hour !== '' ? `${hour}:` : ''
    return `${time}${min}:${seco}`
  }

  //UI界面
  build() {
    Column() {
      Stack() {
        Video({
          src: this.videoSrc, //文件路径
          currentProgressRate: this.curRate, //视频播放倍速。number取值仅支持:0.75,1.0,1.25,1.75,2.0。
          previewUri: this.previewUri, //视频未播放时的预览图片路径
          controller: this.controller, //设置视频控制器,可以控制视频的播放状态。

        })
          .width('100%')
          .height('100%')
          .autoPlay(this.isAutoPlay)
          .controls(this.showControls)
          .onPrepared((e) => {
            this.totalTime = e.duration
            this.videoDuration = this.getDuration(e.duration)
            this.ProgressTotal = this.totalTime
          })
          .onUpdate((e) => {
            this.videoDurationEnd = this.getDuration(Number(this.totalTime) - Number(e.time))
            this.ProgressValue = Number(e.time)
          })
          Column() {
            Row() {
              Text(this.videoDuration)
                .fontSize(12)
                .fontColor('#fff')
                .width(this.isLandSpace ? '5%' : '12%')
                .textAlign(TextAlign.Center)
              Row() {
                Progress({ value: this.ProgressValue, total: this.ProgressTotal, type: ProgressType.Linear })
                  .width('100%')
                  .backgroundColor('rgba(248, 247, 247, 0.51)')
              }
              .width(this.isLandSpace ? '90%' : '76%')

              Text(this.videoDurationEnd)
                .fontSize(12)
                .fontColor('#fff')
                .width(this.isLandSpace ? '5%' : '12%')
                .margin({ left: 5 })
            }
            .width('100%')
            .padding({ top: 5 })

            Row() {
              Flex({ justifyContent: FlexAlign.SpaceBetween }) {
                Row() {
                  Image($r('app.media.previous')).width(25).height(25)
                    .onClick(() => {
                      this.getVideo('left')
                    })
                  Image(!this.isStart ? $r('app.media.start') : $r('app.media.stop')).width(20).height(20)
                    .margin({ left: 10, right: 10 })
                    .onClick(() => {
                      if (!this.isStart) {
                        //开始播放
                        this.controller.start()
                        this.isStart = true
                      } else {
                        //暂停播放,显示当前帧,再次播放时从当前位置继续播放。
                        this.controller.pause()
                        this.isStart = false
                      }
                    })
                  Image($r('app.media.next')).width(20).height(20)
                    .onClick(() => {
                      this.getVideo('right')
                    })
                  Image(!this.isMute ? $r('app.media.no_mute') : $r('app.media.mute')).width(20).height(20)
                    .margin({ left: 10, right: 10 })
                    .onClick(() => {
                      this.isMute = !this.isMute
                    })
                  Text(`${this.curRateName}x`)
                    .width(50)
                    .height(25)
                    .fontSize(14)
                    .fontColor('#fff')
                    .margin({ left: 20, right: 15 })
                    .onClick(() => {
                      this.isSHowCurRateList = !this.isSHowCurRateList
                    })
                  if (this.isSHowCurRateList) {
                    List() {
                      ForEach(this.PlaybackSpeedList, (item: backSpeedInfo) => {
                        ListItem() {
                          Text(`${item.name}`)
                            .fontSize(15)
                            .fontColor('#fff')
                            .textAlign(TextAlign.Center)
                            .width('100%')
                            .onClick(() => {
                              this.curRate = item.curRate
                              this.curRateName = item.name
                              this.isSHowCurRateList = false
                            })
                        }
                      })
                    }
                    .width(40)
                    .height(100)
                    .margin({ left: -70, top: -140 })
                    .backgroundColor('rgba(12, 12, 12, 0.5)')
                    .padding(5)
                  }
                }

                Image(!this.isFullscreen ? $r('app.media.cancel_big_window') : $r('app.media.big_window'))
                  .width(25)
                  .height(25)
                  .onClick(() => {
                    if (!this.isFullscreen) {
                      this.isFullscreen = true
                    } else {
                      this.isFullscreen = false
                    }
                    this.setWindowFullscreen()
                  })
              }
            }
            .width('100%')
            .height('13%')
          }
          .height('100%')
          .padding({ left: 10, right: 10 })
          .justifyContent(FlexAlign.End)
          .visibility(this.isShowVideoControls ? Visibility.Visible : Visibility.None)
      }
      .height(this.videoHeight)
      .onClick(() => {
        this.isShowVideoControls = !this.isShowVideoControls
        console.log('isShowVideoControls',this.isShowVideoControls)
      })
    }
    .height('100%')
  }
}

//为video定义的class类
export class videoInfo {
  videoSrc: Resource;
  previewUri: Resource;

  constructor(videoSrc: Resource, previewUri: Resource) {
    this.videoSrc = videoSrc
    this.previewUri = previewUri
  }
}

export class backSpeedInfo {
  name: number;
  curRate: PlaybackSpeed;

  constructor(name: number, curRate: PlaybackSpeed) {
    this.name = name
    this.curRate = curRate
  }
}