鸿蒙自定义Video播放器

2024-01-24

前言

DevEco Studio版本:4.0.0.600

使用效果

如何使用

参考文档: OpenHarmony Video使用说明

1、module创建

File-->New-->Module,选择Static Library

2、相关类创建

PlayControl: 视频播放控制类

PlayProgress: 视频播放器进度条

VideoConstant: 视频播放状态配置类

VideoPlayer: 视频播放器管理类

然后在 VideoLibrary Index.ets 类中添加对外输出的引用

export { VideoPlayer } from './src/main/ets/VideoPlayer'

PlayControl类:

import { VideoConstant } from './VideoConstant';

/**
 * 播放控制器
 */
@Component
export struct PlayControl {
   private playVideoModel?: VideoController;
   @Link videoStatus: number

   build() {
      Row() {
         Image(this.videoStatus == VideoConstant.STATUS_START ? $r('app.media.start_press') : $r('app.media.video_play_press'))
            .width('92px')
            .height('92px')
            .margin({ left: '156px', right: '156px' })
            .onClick(() => {
               if (this.videoStatus == VideoConstant.STATUS_START) {
                  this.videoStatus = VideoConstant.STATUS_PAUSE
                  if (this.playVideoModel != undefined) {
                     this.playVideoModel.pause()
                  }
               } else {
                  this.videoStatus = VideoConstant.STATUS_START
                  if (this.playVideoModel != undefined) {
                     this.playVideoModel.start()
                  }
               }
            })
      }
   }
}

PlayProgress类:

/**
 * 播放进度条
 */
@Component
export struct PlayProgress {
   @Prop currentTime: number
   @Prop totalTime: number
   private playVideoModel?: VideoController;

   build() {
      Row() {
         Text(this.formatTime(this.currentTime))
            .fontSize('14px')
            .fontColor(Color.White)
            .margin({ left: '16px', right: '12px' })
         Slider({
            value: this.currentTime, //当前进度值
            max: this.totalTime, //最大值,默认值100
            step: 1, //设置Slider滑动步长
            style: SliderStyle.OutSet //设置Slider的滑块与滑轨显示样式。
         })
            .blockColor(Color.White)//设置滑块的颜色。
            .trackColor($r('app.color.track_color'))//设置滑轨的背景颜色
            .selectedColor(Color.White)//设置滑轨的已滑动部分颜色
            .trackThickness(2)//设置滑轨的粗细
            .layoutWeight(1)
            .height('60px')
            .onChange((value: number, mode: SliderChangeMode) => {
               if (this.playVideoModel != undefined) {
                  this.playVideoModel.setCurrentTime(value, SeekMode.Accurate) // 精准跳转到视频的10s位置
               }
            })
         Text(this.formatTime(this.totalTime))
            .fontSize('14px')
            .fontColor(Color.White)
            .margin({ left: '12px', right: '16px' })
      }
      .width('100%')
      .backgroundColor('#88000000')
   }

   /**
    * 格式化时间
    */
   private formatTime(time: number): string {
      if (time < 60) {
         if (time > 9) {
            return '00:' + time
         } else {
            return '00:0' + time
         }
      } else {
         let timeStr = ''
         let hours = Number.parseInt((time / 60).toString())
         let seconds = time % 60
         if (hours > 9) {
            timeStr = hours.toString()
         } else {
            timeStr = '0' + hours
         }
         if (seconds > 9) {
            timeStr = timeStr + ':' + seconds
         } else {
            timeStr = timeStr + ':0' + seconds
         }
         return timeStr
      }
   }
}

VideoConstant类:

export class VideoConstant {
   /**
    * 开始播放
    */
   static readonly STATUS_START: number = 1;

   /**
    * 暂停播放
    */
   static readonly STATUS_PAUSE: number = 2;

   /**
    * 停止播放
    */
   static readonly STATUS_STOP: number = 3;
}

VideoPlayer类:

import router from '@ohos.router'
import { PlayControl } from './video/PlayControl'
import { PlayProgress } from './video/PlayProgress'
import { VideoConstant } from './video/VideoConstant'

@Preview
@Component
export struct VideoPlayer {
   private videoWidth: Length = '1024px'
   private videoHeight: Length = '550px'
   //视频未播放时的预览图片路径,默认不显示图片
   private previewUris?: Resource
   //视频播放源的路径,支持本地视频路径和网络路径
   @Prop innerResource: Resource
   //设置是否循环播放
   private isLoop: boolean = false
   //设置是否静音
   private isMuted: boolean = false
   //设置是否自动播放
   private isAutoPlay: boolean = true
   //视频控制器,可以控制视频的播放状态
   private controller: VideoController = new VideoController()
   //是否显示控制视图
   @State isShowController: boolean = true
   //视频播放状态
   @State videoStatus: number = VideoConstant.STATUS_STOP
   //视频时长,单位:秒(S)
   @State duration: number = 0
   //视频播放当前时间,单位:秒(S)
   @State currentTime: number = 0

   build() {
      Stack() {
         Video({
            src: this.innerResource,
            previewUri: this.previewUris,
            controller: this.controller
         })
            .muted(this.isMuted)//设置是否静音
            .loop(this.isLoop)//设置是否循环播放
            .autoPlay(this.isAutoPlay)//设置是否自动播放
            .controls(false)//设置是否显示默认控制条
            .objectFit(ImageFit.Contain)//设置视频适配模式
            .width('100%')
            .height('100%')
            .onTouch((event) => {
               if (event.type == TouchType.Up) {
                  this.isShowController = true
               }
            })
            .onStart(() => { //播放时触发该事件。
               console.info('VideoCreateComponent---   onStart')
               this.videoStatus = VideoConstant.STATUS_START
            })
            .onPause(() => { //播放时触发该事件。
               console.info('VideoCreateComponent---   onPause')
               this.videoStatus = VideoConstant.STATUS_PAUSE
            })
            .onFinish(() => { //播放结束时触发该事件。
               console.info('VideoCreateComponent---   onFinish')
               this.videoStatus = VideoConstant.STATUS_STOP
            })
            .onError(() => { //播放失败时触发该事件。
               console.info('VideoCreateComponent---   onError')
            })
            .onPrepared((e) => { //视频准备完成时触发该事件,通过duration可以获取视频时长,单位为秒(s)
               console.info('VideoCreateComponent---   onPrepared is ' + e.duration)
               this.duration = e.duration
            })
            .onSeeking((e) => { //操作进度条过程时上报时间信息,单位为s。
               console.info('VideoCreateComponent---   onSeeking is ' + e.time)
            })
            .onSeeked((e) => { //操作进度条完成后,上报播放时间信息,单位为s
               console.info('VideoCreateComponent---   onSeeked is ' + e.time)
            })
            .onUpdate((e) => { //播放进度变化时触发该事件,单位为s。
               console.info('VideoCreateComponent---   onUpdate is ' + e.time)
               this.currentTime = e.time
            })

         RelativeContainer() {
            Image($r('app.media.video_back'))
               .width('48px')
               .height('48px')
               .alignRules({
                  top: { anchor: '__container__', align: VerticalAlign.Top },
                  left: { anchor: '__container__', align: HorizontalAlign.Start }
               })
               .margin({ left: '48px', top: '24px' })
               .id('imageBack')
               .onClick(() => {
                  router.back()
               })

            PlayControl({ playVideoModel: this.controller, videoStatus: $videoStatus })
               .id('playControl')
               .alignRules({
                  middle: { anchor: '__container__', align: HorizontalAlign.Center },
                  center: { anchor: '__container__', align: VerticalAlign.Center }
               })

            PlayProgress({ playVideoModel: this.controller, totalTime: this.duration, currentTime: this.currentTime })
               .id('playProgress')
               .alignRules({
                  middle: { anchor: '__container__', align: HorizontalAlign.Center },
                  bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
               })

         }.width('100%')
         .height('100%')
         .visibility(this.isShowController ? Visibility.Visible : Visibility.None)
         .onTouch((event) => {
            if (event.type == TouchType.Up) {
               this.isShowController = false
            }
         })
      }
      .width(this.videoWidth)
      .height(this.videoHeight)
   }
}

资源引用:

start_press.png

video_back.png

video_play_press.png

3、在Entry中引用HttpLibaray

参考链接: 静态har共享包

Entry 目录下的 oh-package.json5 文件中添加对VideoLibaray的引用,详细操作参考之前文章。

"dependencies": {
  "@app/videoLibrary": "file:../VideoLibrary"
}

4、代码调用

import { VideoPlayer } from "@app/videoLibrary"

@Entry
@Component
struct Index {
   build() {
      Stack() {
         VideoPlayer({
            // previewUris: $r('app.media.preview'), //未播放时的封面
            innerResource: $rawfile('adv_test_video.mp4')
         })
      }
      .width('100%')
      .height('100%')
   }
}
属性 是否必须 描述
videoWidth 非必须 视频播放器宽度
videoHeight 非必须 视频播放器高度
previewUris 非必须 视频未播放时的预览图片路径,默认不显示图片
innerResource 必须 视频播放源的路径,支持本地视频路径和网络路径
isLoop 非必须 设置是否循环播放
isMuted 非必须 设置是否静音
isAutoPlay 非必须 设置是否自动播放

因为我们的视频是横屏播放的,所以需要配置下界面横屏显示

可以参考之前的文章 OpenHarmony 实现屏幕横竖屏_openharmony 屏幕旋转-CSDN博客

横屏配置:在Entry目录下src/main/module.json5中的 abilities 添加 orientation 属性

其实鸿蒙官方提供了两种方式播放视频:Video组件、AVPlayer,上面的示例是以Video组件进行封装的,感兴趣的同学可以尝试用AVPlayer进行封装下。

我在尝试用AVPlayer进行视频播放时发现,其seek方法定位不准,大家在调用时也可以关注下这个问题。如果你这边解决了,可以在下方留言说明下如何解决的,感谢!!!

参考文档 OpenHarmony 视频播放

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

鸿蒙自定义Video播放器 的相关文章

随机推荐

  • java 企业工程管理系统软件源码 自主研发 工程行业适用

    工程项目管理软件 工程项目管理系统 对建设工程项目管理组织建设 项目策划决策 规划设计 施工建设到竣工交付 总结评估 运维运营 全过程 全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一 系统管理 1 数据字典 实现对数据字典标签
  • 2024年华为OD机试真题-查找接口成功率最优时间段-Python-OD统一考试(C卷)

    题目描述 服务之间交换的接口成功率作为服务调用关键质量特性 某个时间段内的接口失败率使用一个数组表示 数组中每个元素都是单位时间内失败率数值 数组中的数值为0 100的整数 给定一个数值 minAverageLost 表示某个时间段内平均失
  • 题解 | #翻转单词序列# 复习Java几个集合方法使用

    人生第一次面试gg 字节跳动 复活赛 二面 字节后端实习面试 字节飞书后端一面凉经 字节 客服平台 一面面经 已挂 菜鸟前端 避雷避雷中华财险 中厂大厂到底怎么选 樊登读书精准营销岗面经 跨行 转技术岗进大厂的好机会 来看 岗位名称 云 软
  • 【永磁同步电机(PMSM)矢量控制】PMSM电机的速度由矢量控制来控制研究(Simulink仿真实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Simulink仿真实现
  • Airtest自动化测试工具

    一开始知道Airtest大概是在年初的时候 当时 看了一下官方的文档 大概是类似Sikuli的一个工具 主要用来做游戏自动化的 通过截图的方式用来解决游戏自动化测试的难题 最近 移动端测试的同事尝试用它的poco库来做自动化 看样子还不错
  • 【无标题】

    大家都知道该赛项的规程和样题向来都是模棱两可 从来不说具体的内容 导致选手在备赛时没有头绪 不知道该怎么训练 到了赛时发现题目和备赛的时候完全不一样 那么本文将以往年信息安全管理与评估赛项经验来解读今年2023年国赛的规程 帮助选手们指明方
  • 5_机械臂运动学基础_矩阵

    上次说的向量空间是为矩阵服务的 1 学科回顾 从科技实践中来的数学问题无非分为两类 一类是线性问题 一类是非线性问题 线性问题是研究最久 理论最完善的 而非线性问题则可以在一定基础上转化为线性问题求解 线性变换 数域 F 上线性空间V中的变
  • 题解 | #每个创作者每月的涨粉率及截止当前的总粉丝量#

    提前实习把工作实习没了 提前实习把工作实习没了 提前实习把工作实习没了 学校导师个人主页挂了我的牛客经验贴 接一下自己去年的好运 求求oc真的磕头了 来个offer 明天发offer 心想事成 跨行 转技术岗进大厂的好机会 来看 up 提前
  • java毕业设计

    包含部署视频 1 基于ssh的婴幼儿产品销售系统毕业设计 项目报告 答辩PPT 源代码 数据库 截图 部署视频 2 基于jsp的医院管理住院系统毕业设计 项目报告 答辩PPT 源代码 数据库 部署视频 3 基于ssh的医院在线挂号系统毕业设
  • C# Break 和 Continue 语句以及数组详解

    C Break 它被用于 跳出 switch 语句 break 语句也可用于跳出循环 以下示例在 i 等于 4 时跳出循环 示例 for int i 0 i lt 10 i if i 4 break Console WriteLine i
  • 题解 | #翻转单词序列# 复习Java几个集合方法使用

    人生第一次面试gg 字节跳动 复活赛 二面 字节后端实习面试 字节飞书后端一面凉经 字节 客服平台 一面面经 已挂 菜鸟前端 避雷避雷中华财险 中厂大厂到底怎么选 樊登读书精准营销岗面经 跨行 转技术岗进大厂的好机会 来看 岗位名称 云 软
  • 每天10个前端小知识 <Day 14>

    前端面试基础知识题 1 CSSOM树和DOM树是同时解析的吗 浏览器会下载HTML解析页面生成DOM树 遇到CSS标签就开始解析CSS 这个过程不会阻塞 但是如果遇到了JS脚本 此时假如CSSOM还没有构建完 需要等待CSSOM构建完 再去
  • 软件测试面试:还没有自动化测试项目经验,3个项目帮你走入软测职场!

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 CSDN博客 文章浏览阅读2 3k次 点赞85次 收藏11次 你知不知道有这么一个软件测试面试的刷题小程序 里面包含了面试常问的软件测试基础题 web自
  • AI新年头像模板在哪找?告别单调头像的工具分享

    农历新年到啦 今年的春节假期你有没有弄一些氛围装饰呀 除了每年都有的对联 福字等 经典皮肤 现在也流行起给自己的账号营造一些过年的感觉啦 说到这个 很多人第一反应就是给自己换个新年头像 限定皮肤 不过头像要怎么营造新年的感觉呢 其实用AI工
  • 鸿蒙自定义Http网络访问组件

    前言 DevEco Studio版本 4 0 0 600 使用效果 如何使用 参考文档 OpenHarmony http数据请求 1 module创建 File gt New gt Module 选择Static Library 2 相关类
  • 带你理解双路运算放大器LM258DR2G知识讲解

    LM258DR2G此双路运算放大器使用适用于四路运算放大器的电路设计 具有低漏功率 扩展至接地 VEE 的共模输入电压范围以及单电源或分离电源运行 此类器件与单电源应用中的标准运算放大器类型相比 具有若干不同的优点 它们可以在低至 3 0
  • 【产品兼容认证】WhaleStudio 成功兼容TiDB数据库软件

    平凯星辰和白鲸开源宣布成功完成产品兼容认证 北京 2023年12月27日 平凯星辰 北京 科技有限公司 以下简称平凯星辰 旗下的 TiDB 产品与白鲸开源的 WhaleStudio 已成功完成产品兼容性认证 这一重要合作旨在为全球客户提供更
  • 国产化率100%,北斗导航单日定位4500亿次,外媒:GPS将被淘汰

    追赶30年的技术差距 国产卫星导航系统 北斗 开始扬眉吐气 数据显示 北斗导航目前单日定位量达4500亿次 已经获得100多个国家的合作意向 甚至国际民航也摒弃以往 独宠 GPS的惯例 将北斗纳入参考标准 对此 有媒体直言 GPS多年来的技
  • ESM10A 消除对单独 PLC 的需求

    ESM10A 消除对单独 PLC 的需求 ESM10A 可以消除对单独 PLC 的需求 该程序是在 PC 上开发的 然后使用免费提供的简单易用的 EzSQ 软件下载到逆变器 似乎这些改进还不够 日立还在 SJ700 中添加了其他新功能 例如
  • 鸿蒙自定义Video播放器

    前言 DevEco Studio版本 4 0 0 600 使用效果 如何使用 参考文档 OpenHarmony Video使用说明 1 module创建 File gt New gt Module 选择Static Library 2 相关