前言

OpenHarmony 视频播放将视频数据转码并输出到设备进行播放,同时管理播放任务,注册播放监听回调等。本文将带大家学习如何搜索视频并对视频播放全流程场景开发进行介绍说明。

API和组件介绍

OpenHarmony 视频播放功能需要调用媒体服务接口、媒体库管理接口等API和组件实现完整的视频播放操作和使用。

视频播放组件架构图

 

视频播放状态机

 

兼容性

推荐使用视频软件主流的播放格式和主流分辨率,不建议开发者自制非常或者异常码流,以免产生无法播放、卡住、花屏等兼容性问题。

主流的播放格式和主流分辨率:

视频容器规格 规格描述 分辨率
mp4 视频格式:H264/MPEG2/MPEG4/H263 音频格式:AAC/MP3 主流分辨率,如1080P/720P/480P/270P
mkv 视频格式:H264/MPEG2/MPEG4/H263 音频格式:AAC/MP3 主流分辨率,如1080P/720P/480P/270P
ts 视频格式:H264/MPEG2/MPEG4 音频格式:AAC/MP3 主流分辨率,如1080P/720P/480P/270P
webm 视频格式:VP8 音频格式:VORBIS 主流分辨率,如1080P/720P/480P/270P

开发流程

  1. 在配置文件中添加视频播放需要的权限,编写用户授权逻辑;

  2. 在页面中添加 XComponent 组件或者 Video组件;

  3. 获取媒体库实例;

  4. 搜索文件资源;

  5. 把文件地址放入 VideoPlayer 或者 Video组件;

  6. 编写播放、暂停、循环播放和监听等逻辑。

权限

视频播放需要用户授予相应的权限后才能使用媒体库资源或网络资源,如果用户不同意授权,应用是无法使用媒体库资源或网络资源。

需要的权限:

  • 网络权限: ohos.permission.INTERNET

  • 媒体和文件操作权限: ohos.permission.MEDIA_LOCATION, ohos.permission.READ_MEDIA, ohos.permission.WRITE_MEDIA

相关文档:访问控制开发概述

配置权限

在进行视频播放开发前需要先在配置文件中配置需要的权限信息。

Stage 模型配置 module.json5

{     "module":{         ...         "requestPermissions": [            {                 "name": "ohos.permission.INTERNET"            },            {                 "name": "ohos.permission.MEDIA_LOCATION"            },            {                 "name": "ohos.permission.READ_MEDIA"            },            {                 "name": "ohos.permission.WRITE_MEDIA"            }          ]    }     ... }

FA 模型配置 config.json

{     ...     "module":{         ...         "reqPermissions": [            {                 "name": "ohos.permission.INTERNET"            },            {                 "name": "ohos.permission.MEDIA_LOCATION"            },            {                 "name": "ohos.permission.READ_MEDIA"            },            {                 "name": "ohos.permission.WRITE_MEDIA"            }                    ]    }     ... }

请求用户授权

获取 AbilityContext

Stage 模型通过继承 Ability 接口,在 Ability 被拉起时获取上下文环境。

export default class MainAbility extends Ability {     onCreate(want, launchParam) {         globalThis.context = this.context    } }

FA 模型通过 FeatureAbility API 获取上下文环境。

import FeatureAbility from '@ohos.ability.featureAbility'  globalThis.context = FeatureAbility.getContext()

获取 bundleName

Stage 模型通过 Context 可以直接获取到当前应用包名信息。

const bundleName = globalThis.context.abilityInfo.bundleName

FA 模型通过 getBundleName 接口获取当前应用包名信息。

const bundleName = globalThis.context.getBundleName()

获取 accessTokenId

根据给定的包名获取 ApplicationInfo (应用程序信息),其中包含字段:accessTokenId

accessTokenId 是应用在安装时由系统分配的唯一标识,重新安装会刷新。

import Bundle from '@ohos.bundle'  const appInfo = Bundle.getApplicationInfo(bundleName: string, bundleFlags: number, userId?: number): Promise<ApplicationInfo>  const accessTokenId = appInfo.accessTokenId

校验应用是否授予权限

  1. 获取访问控制模块对象。

import AbilityAccessCtrl from '@ohos.abilityAccessCtrl'  AtManager = AbilityAccessCtrl.createAtManager()
  1. 校验应用是否授予权限, tokenID 为应用程序的 accessTokenId,permissionName 为权限名称。

AtManager.verifyAccessToken(tokenID: number, permissionName: string): Promise<GrantStatus>

GrantStatus 说明

export enum GrantStatus { // access_token permission check fail PERMISSION_DENIED = -1, // access_token permission check success PERMISSION_GRANTED = 0, }

动态申请权限

拉起弹窗请求用户授权,传入需要申请的权限数组,得到用户授权结果。

Context.requestPermissionsFromUser(permissions: Array<string>) : Promise<PermissionRequestResult>;

PermissionRequestResult 说明

interface PermissionRequestResult { requestCode: number; // 用户传入的权限数组 permissions: Array<string>; // 相应请求权限的结果数组。0表示授权成功,-1表示失败 authResults: Array<number>; }

请求用户授权代码示例

Stage 模型为例:

Module 配置文件:module.json5 Ability 生命周期管理类:MainAbility.ts 请求用户授权页面:Permission.ets

获取媒体库资源

通过媒体库管理器搜索媒体视频资源。

  1. 获取媒体库的实例,用于访问和修改用户等个人媒体数据信息(如音频、视频、图片、文档等)。

import MediaLibrary from '@ohos.multimedia.mediaLibrary'; mediaLib = MediaLibrary.getMediaLibrary(context: Context): MediaLibrary
  1. 获取文件检索结果集。

fetchFileResult = await getFileAssets(options: MediaFetchOptions): Promise<FetchFileResult>
  1. 获取文件资源

fileAsset = await fetchFileResult.getFirstObject(): Promise<FileAsset>
  1. 获取视频播放地址

uri = fileAsset.uri

获取视频播放资源代码示例

Stage 模型为例:

获取视频播放资源页面:FileAsset.ets

Video 组件

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

在页面 build 中添加 Video 组件

controller: VideoController = new VideoController() Video({ src: this.src, previewUri: this.previewUri, currentProgressRate: this.currentProgressRate, controller: this.controller }) .muted(this.muted) .autoPlay(this.autoPlay) .controls(this.controls) .objectFit(this.objectFit) .loop(this.loop) .onStart(() => { console.log('onStart'); }) .onPause(() => { console.log('onPause'); }) .onFinish(() => { console.log('onFinish'); }) .onError(() => { console.error('onError'); }) .onPrepared((e) => { console.log('onPrepared is ' + e.duration); }) .onSeeking((e) => { console.log('onSeeking is ' + e.time); }) .onSeeked((e) => { console.log('onSeeked ' + e.time); }) .onUpdate((e) => { console.log('onUpdate ' + e.time); })

VideoOptions

参数名 参数类型 必填 默认值 参数描述
src string | Resource - 视频播放源的路径,支持本地视频路径和网络路径。 支持在resources下面的video或rawfile文件夹里放置媒体资源。 支持dataability://的路径前缀,用于访问通过Data Ability提供的视频路径。
currentProgressRate number | PlaybackSpeed 1.0 | PlaybackSpeed. Speed_Forward_1_00_X 视频播放倍速。
previewUri string | PixelMap | Resource - 预览图片的路径。
controller VideoController - 控制器。

属性

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

事件

名称 功能描述
onStart() => void 播放时触发该事件。
onPause() => void 暂停时触发该事件。
onFinish() => void 播放结束时触发该事件。
onError() => void 播放失败时触发该事件。
onPrepared(event?: { duration: number }) => void 视频准备完成时触发该事件,通过duration可以获取视频时长,单位为秒(s)。
onSeeking(event?: { time: number }) => void 操作进度条过程时上报时间信息,单位为s。
onSeeked(event?: { time: number }) => void 操作进度条完成后,上报播放时间信息,单位为s。
onUpdate(event?: { time: number }) => void 播放进度变化时触发该事件,单位为s,更新时间间隔为250ms。

VideoController

start

start(): void

开始播放。

pause

pause(): void

暂停播放。

stop

stop(): void

停止播放。

requestFullscreen

requestFullscreen(value: boolean)

请求全屏播放。

参数:

参数名 参数类型 必填 默认值 参数描述
value boolean false 是否全屏播放。

exitFullscreen

exitFullscreen()

退出全屏播放。

setCurrentTime

setCurrentTime(value: number)

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

参数:

参数名 参数类型 必填 默认值 参数描述
value number - 视频播放进度位置。

setCurrentTime

setCurrentTime(value: number, seekMode: SeekMode)

指定视频播放的进度位置,并指定跳转模式。

参数:

参数名 参数类型 必填 默认值 参数描述
value number - 视频播放进度位置。
seekMode SeekMode - 跳转模式。

SeekMode 说明:

名称 描述
PreviousKeyframe 跳转到前一个最近的关键帧。
NextKeyframe 跳转到后一个最近的关键帧。
ClosestKeyframe 跳转到最近的关键帧。
Accurate 精准跳转,不论是否为关键帧。

Video组件代码示例

Stage 模型为例:

Video组件页面:Video_Compoment.ets

VideoPlayer 播放器

视频播放管理类,用于管理和播放视频媒体。

XComponent 组件

  1. 在页面 build 中添加 XComponent 组件

XComponent 可用于EGL/OpenGLES和媒体数据写入,并显示在XComponent组件,相机中使用 XComponent 组件来展示预览图像数据。

xComponentController: XComponentController = new XComponentController() XComponent({ id: '', type: 'surface', controller: this.xComponentController }).onLoad(() => {})

XComponent 的 width 和 height 可以随页面逻辑需要设置。

  1. 获取 XComponent 对应 Surface 的 ID

xComponentController.getXComponentSurfaceId(): string
  1. 设置 XComponent 持有 Surface 的宽度和高度

xComponentController.setXComponentSurfaceSize(value: {surfaceWidth: number, surfaceHeight: number}): void

Surface:用于管理和传递图形和媒体的共享内存。具体场景包括图形的送显、合成,媒体的播放、录制等。 Surface 的 width 和 height 不可随意设置,需要设置视频的宽和高。

VideoPlayer

一个简单的播放器

  1. 创建 Video 播放管理类

videoPlayer = await Media.createVideoPlayer() : Promise<VideoPlayer>
  1. 设置视频媒体 URL

this.videoPlayer.src = 'fd://xx'
  1. 设置 SurfaceId

this.videoPlayer.setDisplaySurface(surfaceId: string): Promise<void>

SurfaceId 从 XComponent 组件控制器获取。 SetDisplaySurface 需要在设置 url 和 Prepare 之间,无音频的视频流必须设置 Surface 否则 Prepare 失败。

  1. 准备播放视频

this.videoPlayer.prepare(callback: AsyncCallback<void>): void
  1. 开始播放视频

this.videoPlayer.play(): Promise<void>;

属性

名称 类型 可读 可写 说明
url string 视频媒体URL,支持当前主流的视频格式(mp4、mpeg-ts、webm、mkv)。
loop boolean 视频循环播放属性,设置为'true'表示循环播放。
currentTime number 视频的当前播放位置。
duration number 视频时长,返回-1表示直播模式。
state VideoPlayState 视频播放的状态。
width number 视频宽。
height number 视频高。

事件

名称 功能描述
on(type: 'playbackCompleted', callback: Callback<void>): void 开始监听视频播放完成事件。
on(type: 'bufferingUpdate', callback: (infoType: BufferingInfoType, value: number) => void): void 开始监听视频缓存更新事件。
on(type: 'startRenderFrame', callback: Callback<void>): void 开始监听视频播放首帧送显上报事件。
on(type: 'videoSizeChanged', callback: (width: number, height: number) => void): void 开始监听视频播放宽高变化事件。
on(type: 'error', callback: ErrorCallback): void 开始监听视频播放错误事件。
on(type: 'availableBitrateCollected', callback: (bitrates: Array<number>) => void): void 开始监听视频播放码率上报事件。

setDisplaySurface

setDisplaySurface(surfaceId: string): Promise<void>

设置SurfaceId。

注意:SetDisplaySurface需要在设置url和Prepare之间,无音频的视频流必须设置Surface否则Prepare失败。

参数:

参数名 类型 必填 说明
surfaceId string SurfaceId
callback function 设置SurfaceId的回调方法。

prepare

prepare(): Promise<void>

准备播放视频。

参数:

参数名 类型 必填 说明
callback function 准备播放视频的回调方法。

play

play(callback: AsyncCallback<void>): void;

开始播放视频。

参数:

参数名 类型 必填 说明
callback function 开始播放视频的回调方法。

pause

pause(callback: AsyncCallback<void>): void

暂停播放视频。

参数:

参数名 类型 必填 说明
callback function 暂停播放视频的回调方法。

stop

stop(callback: AsyncCallback<void>): void

停止播放视频。

参数:

参数名 类型 必填 说明
callback function 停止播放视频的回调方法。

reset

reset(callback: AsyncCallback<void>): void

切换播放视频。

参数:

参数名 类型 必填 说明
callback function 切换播放视频的回调方法。

seek

seek(timeMs: number, mode:SeekMode, callback: AsyncCallback<number>): void

跳转到指定播放位置。

参数:

参数名 类型 必填 说明
timeMs number 指定的跳转时间节点,单位毫秒(ms)。
mode SeekMode 跳转模式。
callback function 跳转到指定播放位置的回调方法。

setSpeed

setSpeed(speed:number, callback: AsyncCallback<number>): void

设置播放速度。

参数:

参数名 类型 必填 说明
speed number 指定播放视频速度。
callback function 设置播放速度的回调方法。

selectBitrate

selectBitrate(bitrate:number): Promise<number>

设置码率。

参数:

参数名 类型 必填 说明
bitrate number 指定码率播放,用于hls多码率场景,单位为bps。

getTrackDescription

getTrackDescription(): Promise<Array<MediaDescription>>

获取视频轨道信息。

release

release(): Promise<void>

释放视频资源。

VideoPlayer代码示例

Stage 模型为例:

VideoPlayer页面:Video_Player.ets

参考文献

[1] 视频播放开发指导. https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/media/video-playback.md

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐