[文章]基于ArkTS语言的OpenHarmony APP应用开发:多媒体管理2

阅读量0
0
0

1、程序介绍

本示例展示了视频组件的基本功能,以及如何控制播放状态的相关能力。包括视频组件化,全屏化,窗口化,上下轮播视频等。

本实例使用Video组件,具体如下:

  • 进入首页点击播放按键。
  • 点击视频播放按钮,视频开始播放。再次点击视频进入视频全屏页。
  • 首页下滑500vp后,视频小窗口化。
  • 4.点击直播按钮进入直播页,上下滑动视频。

本案例已在OpenHarmony凌蒙派-RK3568开发板验证通过,具体代码可参考:https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk3568-openharmony/tree/master/samples/d09_VideoShow

API版本:9

2、知识准备

2.1、Video

用于播放视频文件并控制其播放状态的组件。

使用网络视频时,需要申请权限ohos.permission.INTERNET。

详细请参考:官方文档

2.1.1、接口

Video(value: {src?: string | Resource, currentProgressRate?: number | string | PlaybackSpeed, previewUri?: string | PixelMap | Resource, controller?: VideoController})

参数定义如下所示:

参数名 参数类型 必填 参数描述
src string Resource
currentProgressRate number string PlaybackSpeed
previewUri string PixelMap Resource
controller VideoController 设置视频控制器

其中,PlaybackSpeed定义如下所示:

名称 描述
Speed_Forward_0_75_X 0.75倍速播放
Speed_Forward_1_00_X 1倍速播放
Speed_Forward_1_25_X 1.25倍速播放
Speed_Forward_1_75_X 1.75倍速播放
Speed_Forward_2_00_X 2倍速播放

2.1.2、属性

除支持通用属性外,还支持以下属性:

名称 参数类型 描述
muted boolean 是否静音。 默认值:false
autoPlay boolean 是否自动播放。 默认值:false
controls boolean 控制视频播放的控制栏是否显示。 默认值:true
objectFit ImageFit 设置视频显示模式。 默认值:Cover
loop boolean 是否单个视频循环播放。 默认值:false

2.1.3、事件

除支持通用事件外,还支持以下事件:

名称 功能描述
onStart(event:() => void) 播放时触发该事件
onPause(event:() => void) 暂停时触发该事件
onFinish(event:() => void) 播放结束时触发该事件
onError(event:() => void) 播放失败时触发该事件
onPrepared(callback:(event?: { duration: number }) => void) 视频准备完成时触发该事件,通过duration可以获取视频时长,单位为秒(s)
onSeeking(callback:(event?: { time: number }) => void) 操作进度条过程时上报时间信息,单位为s
onSeeked(callback:(event?: { time: number }) => void) 操作进度条完成后,上报播放时间信息,单位为s
onUpdate(callback:(event?: { time: number }) => void) 播放进度变化时触发该事件,单位为s,更新时间间隔为250ms
onFullscreenChange(callback:(event?: { fullscreen: boolean }) => void) 在全屏播放与非全屏播放状态之间切换时触发该事件,返回值为true表示进入全屏播放状态,为false则表示非全屏播放

2.1.4、VideoController

一个VideoController对象可以控制一个或多个video。

(1)导入对象

controller: VideoController = new VideoController()

(2)start

start(): void

开始播放。

(3)pause

pause(): void

暂停播放,显示当前帧,再次播放时从当前位置继续播放。

(4)stop

stop(): void

停止播放,显示当前帧,再次播放时从头开始播放。

2.1.5、exitFullscreen

exitFullscreen()

退出全屏播放。

2.1.6、setCurrentTime

setCurrentTime(value: number)

指定视频播放的进度位置。

其中,参数定义如下:

参数名 参数类型 必填 参数描述
value number 视频播放进度位置,单位为s

3、程序解析

本案例展示了视频组件的基本功能,以及如何控制播放状态的相关能力。包括视频组件化,全屏化,窗口化,上下轮播视频等。

本案例主要分为以下几个部分:

(1)MainPage.ets,负责主页面,通过调用其它自定义控件播放视频;

(2)VideoPage.ets:负责上方轮播图视频播放和控制;

(3)SmallVideo.ets:负责小窗口视频播放和控制;

(4)LivePage.ets:负责显示直播页面;

(5)FullPage.ets:全屏显示视频播放页面;

3.1、申请权限

申请网络视频权限,在entry/src/main/module.json5文件中添加如下内容:

"requestPermissions": [
  {
    "name": "ohos.permission.INTERNET"
  }
]

3.2、MainPage.ets

在entry/src/main/ets/pages/Index.ets文件中调用MainPage自定义组件。

import { MainPage } from "@ohos/video-component"@Entry
@Component
struct Index {
  @State message: string = 'Hello World'build() {
    Column() {
      MainPage()
    }
    .width('100%')
    .height('100%')
  }
}

在VideoComponent/src/main/ets/components/pages/MainPage.ets文件中,首先设置媒体查询的查询条件。

listenerIsPhone = mediaQuery.matchMediaSync('(orientation:landscape)');

其次,对监听句柄进行事件绑定。

async aboutToAppear() {
  this.portraitFunc = this.onPortrait.bind(this) // 绑定
  this.listenerIsPhone.on('change', this.portraitFunc)
}

再次,通过调用VideoPage显示轮播图视频播放。

Swiper() {
  // 视频界面,调用自定义的VideoPage.ets
  VideoPage({ isStart: $openFirst })
  // 模拟Swiper数据
  LazyForEach(new MyDataSource(this.arrSwiper), (item) => {
    Text(item.toString())
      .width('100%')
      .aspectRatio(1.12)
      .backgroundColor(0xAFEEEE)
      .textAlign(TextAlign.Center)
      .fontSize(20)
  }, item => item)
}

再次,调用SmallVideo显示小视频播放。

Column() {
  SmallVideo({ isHidden: $isHidden, isCancel: $isCancel })
}
.width('100%')
.alignItems(HorizontalAlign.End)

最后,显示直播视频按键。

Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
  Image($r('app.media.broadcast'))
    .objectFit(ImageFit.Contain)
    .width('24')
    .height('24')
    .margin({ top: 10 })
  Text($r("app.string.in_live"))
    .fontSize(10)
    .fontColor('#000000')
    .margin({ top: 5 })
}
.width(58)
.height(58)
.backgroundColor('#FFFFFF')
.border({ color: 'rgba(0,0,0,0.2)' })
.borderRadius(16)
.borderWidth(1.3)
.key('directVideo')
.onClick(() => {
  router.push({ url: 'pages/LivePage' })
})
.position({ x: '86%', y: '20%' })
}.width('100%').height('100%').backgroundColor(0xDCDCDC)

注意:当Flex触发鼠标按下事件,则通过router.push()跳转到LivePage.ets页面。

3.3、VideoPage.ets

首先,定义播放视频的资源以及视频播放控制器。

@State videoSrc: Resource = $rawfile('video_4.mp4')   // 视频播放文件
detailVideoController: VideoController = new VideoController()  // 设置视频播放的控制器,比如控制视频开始,暂停等

其次,调用Video组件,并将视频资源和视频控制器代入。

Video({
  src: this.videoSrc,                       // 设置视频文件地址
  controller: this.detailVideoController,   // 设置视频播放的控制器,比如控制视频开始,暂停等
})

最后,通过video组件的.onClick()响应事件,控制视频播放。

.onClick(() => {                          // 单击按钮事件
  if (this.isPlayClick) {                 // 判断play按钮是否用过,没有用过,进入这层
    if (this.firstClick) {                // 第一次点击视频开始播放,再次点击进入全屏
      this.detailVideoController.start()  // Video开始播放
      this.isHidden = !this.isHidden
      this.isStart = true
      this.firstClick = !this.firstClick
    } else {
      // 页面跳转
      router.push({ url: 'pages/FullPage', params: { videoSrc: this.videoSrc, videoTime: this.updateTime } })
    }
  } else {
    // 页面跳转
    router.push({ url: 'pages/FullPage', params: { videoSrc: this.videoSrc, videoTime: this.updateTime } })
  }
})

其中,关于播放时间显示(即变量updateTime)需要特别注意。在此不赘述。

3.4、SmallVideo.ets

SmallVideo自定义组件则负责小窗口视频播放,通过调用Video播放视频文件。

首先,定义视频资源和视频控制器。

@State smallVideoSrc: Resource = $rawfile('video_4.mp4')        // 视频数据源文件
smallVideoController: VideoController = new VideoController()   // 设置视频控制器

其次,将视频资源和视频控制器放入Video控件。

Video({
  src: this.smallVideoSrc,                // 视频播放源的路径,支持本地视频路径和网络路径
  controller: this.smallVideoController   // 设置视频控制器
})
  .controls(false)
  .autoPlay(true)                         // 设置自动播放
  .muted(true)                            // 设置静音
  .onFinish(() => {                       // 播放结束时触发该事件
    this.isHidden = false
  })

注意:.onFinish()事件是在视频播放完毕后触发。

3.5、LivePage.ets

LivePage.ets负责显示直播页面。

首先,定义一个媒体查询的监听句柄。

listenerIsPhone = mediaQuery.matchMediaSync('(orientation:landscape)');

其次,在aboutToAppear()中将视频播放绑定,并通过http连接请求,获取网络视频信息。

async aboutToAppear() {
  this.portraitFunc = this.onPortrait.bind(this) // bind current js instance
  this.listenerIsPhone.on('change', this.portraitFunc)
​
  try {
    let a = await Live()  // http连接请求
    this.mData = JSON.parse(a.result.toString())
    this.liveInfoList = this.mData.data
  } catch (error) {
    console.log('http resquest is fail:' + error)
  }
}

最后,在build()中显示网络视频直播。

ForEach(this.liveInfoList, (item, index) => {
  Stack() {
    if (this.active == index) {
      Video({ src: item.uri })
        .autoPlay(true)
        .loop(false)
        .controls(false)
        .objectFit(ImageFit.Contain)
        .width('100%')
        .height('100%')
    }
    ......
  }
  ......
}

3.6、FullPage.ets

FullPage.ets负责全屏显示视频播放页面。

首先,定义一个媒体查询的监听句柄和视频控制器。

listenerIsPhone = mediaQuery.matchMediaSync('(orientation:landscape)')
fullVideoController: VideoController = new VideoController()

其次,在aboutToAppear()中绑定当前用例。

aboutToAppear() {
  this.fullParams = router.getParams()
  this.fullSrc = this.fullParams['videoSrc']
  this.playTime = this.fullParams['videoTime']
​
  this.portraitFunc = this.onPortrait.bind(this) // bind current js instance
  this.listenerIsPhone.on('change', this.portraitFunc)
}

最后,调用Video组件控制视频播放。

Video({
  src: this.fullSrc,
  controller: this.fullVideoController
})
  .width('100%')
  .height('100%')
  .autoPlay(true)
  .loop(true)
  .controls(false)
  .objectFit(ImageFit.Contain)
  .onPause(() => {
    this.isHidden = true
  })
  .onFullscreenChange((e) => {
    this.isHidden = false
  })
  .onStart(() => {
    this.isHidden = false
  })
  .onPrepared((e) => {
    this.fullVideoController.setCurrentTime(this.playTime)
    this.maxValue = e.duration
  })
  .onUpdate((e) => {
    this.nowValue = e.time
  })
  .onClick(() => {
    this.fullVideoController.pause();
  })

4、项目编译

4.1、打开项目

打开DevEco Studio,再打开自定义通知项目。

4.2、编译程序

点击菜单栏上的“Build” -> "Rebuild Project"。如果出现无法编译,则注意查看Event Log界面。如下所示:
question_npm_install.png

点击Run 'npm install',让DevEco Studio安装相关依赖包。

重新点击菜单栏上的“Build” -> "Rebuild Project"。出现如下错误:
question_root_module.png
点击上图红色框部分,安装相关服务。

重新点击菜单栏上的“Build” -> "Rebuild Project",编译成功。
rebuild_project_successful.png

4.3、安装程序

点击“entry”按钮,将项目程序安装到设备端。如下图所示:
heap_install_to_device.png
如果出现下述报错,表示无法安装。如图所示:
heap_install_failed.png

点击上图红色框的蓝色字体,弹出"Project Structure"对话框,点击"Apply",再点击"OK"。如图所示:
project_structure.png

重新点击“entry”按钮,将项目程序安装到设备端。
entry_successful.png

5、运行结果

微信截图_20240920111149.png

回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友