HarmonyOS 鸿蒙Next中avPlayer播放视频
HarmonyOS 鸿蒙Next中avPlayer播放视频
一:配置网络权限
module.json5文件中配置网络权限
"requestPermissions": [
{"name": "ohos.permission.INTERNET"}
],
二: 创建 avPlayer 函数
async createAVPlayer() {
if (this.avPlayer) {
return;
}
await media.createAVPlayer().then((player: media.AVPlayer) => {
this.avPlayer = player
console.log(TAG + ' avPlayer创建成功! ');
})
.catch((err: BusinessError) => {
console.error(TAG + ` avPlayer创建异常: errCode:${err.code} errMessage:${err.message}`);
})
}
三:创建状态机
如果播放音频,不传surfaciID参数
如果播放视频,传入surfaceID参数,并在initalized状态中,将surfaceID赋值给avPlayer.surfaceID
理解为: 将 视频流 放入 surfaceID的值为 ‘xx’ 的盒子中播放
//创建状态机
setAVPlayerCallback(avPlayer: media.AVPlayer, surfaceID?: string | undefined) {
// seek操作结果回调函数
avPlayer.on('seekDone', (seekDoneTime: number) => {
console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
});
// error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程
avPlayer.on('error', (err: BusinessError) => {
console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
if (err.code === 5400106) {
showToast('音频地址异常')
}
avPlayer.reset(); // 调用reset重置资源,触发idle状态
});
// 状态机变化回调函数
avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
switch (state) {
case 'idle': // 闲置状态, avplayer刚被创建或者调用reset方法之后进入idle状态
//此状态可设置 url 或者 fdSrc属性,然后自动进入initialized状态
this.setPlayState()
break;
case 'initialized': // 资源初始化,
//此时可以配置 窗口、音频、等静态属性
console.info('AVPlayer state initialized called.');
this.setPlayState()
if (surfaceID) {
avPlayer.surfaceId = surfaceID
}
avPlayer.prepare();
break;
case 'prepared': // 准备完毕状态,此时播放引擎的资源已准备就绪
console.info('AVPlayer state prepared called.');
this.setPlayState()
avPlayer.play(); // 调用播放接口开始播放
break;
case 'playing': // 正在播放状态,可在prepared/paused/completed状态调用play方法,avplayer会进入此状态
this.setPlayState()
break;
case 'paused': // 暂停状态,在playing状态中执行pause方法,会进入paused状态
console.info('AVPlayer state paused called.');
this.setPlayState()
avPlayer.pause()
break;
case 'completed': // 播放至结尾状态, 可调用play方法进入playing状态,调用stop方法进入stopped状态
console.info('AVPlayer state completed called.');
this.setPlayState()
avPlayer.stop(); //调用播放结束接口
break;
case 'stopped': // 停止状态, 可调用prepared/playing/paused/completed状态调用stop方法进入此状态
//此状态只保留属性,但会释放内存资源
//可调用prepared重新准备
//可调用reset重置
//可调用release彻底销毁
console.info('AVPlayer state stopped called.');
this.setPlayState()
avPlayer.reset(); // 调用reset接口初始化avplayer状态
break;
case 'released': //销毁状态
console.info('AVPlayer state released called.');
this.setPlayState()
avPlayer.reset()
break;
default:
console.info('AVPlayer state unknown called.');
break;
}
});
//监听进度条长度
avPlayer.on('durationUpdate', (data: number) => {
this.audioDuration = data
this.setPlayState()
console.log('durationUpdate: ' + JSON.stringify(this.audioDuration));
})
//监听进度条当前位置
avPlayer.on('timeUpdate', (data: number) => {
this.currTimeInAudio = data
console.log('timeUpdate: ' + JSON.stringify(this.currTimeInAudio));
})
}
四: 播放视频函数
创建avPlayer函数
注册状态机
设置视频地址 和 surfaceID
//播放
async play(src: string,surfaceID?:string|undefined) {
//如果avplayer不存在,创建,此时播放状态为 idle: 空闲状态
await this.createAVPlayer()
//设置状态机
this.setAVPlayerCallback(this.avPlayer!,surfaceID);
//设置 音频url,状态自动跳至 initialized
this.avPlayer!.url = src;
}
五: 暂停播放
//暂停播放
pause() {
if (this.avPlayer) {
this.avPlayer.pause()
}
}
六: 停止播放
//停止播放
stop() {
if (this.avPlayer) {
this.avPlayer.stop()
}
}
七: 重置 avPlayer状态
//重置 avplayer 状态
reset() {
if (this.avPlayer) {
this.avPlayer.reset()
}
}
八: 释放 avPlayer
//释放avPlayer
release() {
if (this.avPlayer) {
this.avPlayer.release()
}
}
九:调用方式
//播放音频
AvPlayerUtil._instance.play('视频地址',surfaceID)
//停止音频
AvPlayerUtil._instance.stop()
//暂停播放
AvPlayerUtil._instance.pause()
// 重置 avPlayer状态
AvPlayerUtil._instance.reset()
//释放 avPlayer
AvPlayerUtil._instance.release()
//继续播放
AvPlayerUtil._instance.play()
十: 创建视频播放容器
XComponent({
type: XComponentType.SURFACE,//固定语法
controller: this.xcpController,//XComponentController控制器
})
.width('80%')
.height(200)
.onLoad(() => {
this.surfaceID = this.xcpController.getXComponentSurfaceId()//当 XComponentController 加载完毕之后,获取surfaceID
AvPlayerUtil._instance.play('https://media.w3.org/2010/05/sintel/trailer.mp4', this.surfaceID)//调用播放函数,并传入 视频地址 和 surfaceID 参数
})
.onDestroy(() => {
AvPlayerUtil._instance.release()
})
十一: 工具类完整代码
import { media } from '@kit.MediaKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { audio } from '@kit.AudioKit';
import { showToast } from '../../logic/CommonLogic';
const TAG = '[AvPlayerUtil] '
export class AvPlayerUtil {
private playState?: media.AVPlayerState
private avPlayer?: media.AVPlayer
private audioDuration?: number
private currTimeInAudio?: number
private surfaceID: string | undefined = undefined
public static _instance: AvPlayerUtil = new AvPlayerUtil()
async createAVPlayer() {
if (this.avPlayer) {
return;
}
await media.createAVPlayer().then((player: media.AVPlayer) => {
this.avPlayer = player
console.log(TAG + ' avPlayer创建成功! ');
})
.catch((err: BusinessError) => {
console.error(TAG + ` avPlayer创建异常: errCode:${err.code} errMessage:${err.message}`);
})
}
setPlayState() {
this.playState = this.avPlayer?.state
console.log('PlayState: ' + JSON.stringify(this.playState));
}
// 创建状态机
setAVPlayerCallback(avPlayer: media.AVPlayer, surfaceID?: string | undefined) {
// seek操作结果回调函数
avPlayer.on('seekDone', (seekDoneTime: number) => {
console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
});
// error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程
avPlayer.on('error', (err: BusinessError) => {
console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
if (err.code === 5400106) {
showToast('音频地址异常')
}
avPlayer.reset(); // 调用reset重置资源,触发idle状态
});
// 状态机变化回调函数
avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
switch (state) {
case 'idle': // 闲置状态, avplayer刚被创建或者调用reset方法之后进入idle状态
//此状态可设置 url 或者 fdSrc属性,然后自动进入initialized状态
this.setPlayState()
break;
case 'initialized': // 资源初始化,
//此时可以配置 窗口、音频、等静态属性
console.info('AVPlayer state initialized called.');
this.setPlayState()
if (surfaceID) {
avPlayer.surfaceId = surfaceID
}
avPlayer.prepare();
break;
case 'prepared': // 准备完毕状态,此时播放引擎的资源已准备就绪
console.info('AVPlayer state prepared called.');
this.setPlayState()
avPlayer.play(); // 调用播放接口开始播放
break;
case 'playing': // 正在播放状态,可在prepared/paused/completed状态调用play方法,avplayer会进入此状态
this.setPlayState()
break;
case 'paused': // 暂停状态,在playing状态中执行pause方法,会进入paused状态
console.info('AVPlayer state paused called.');
this.setPlayState()
avPlayer.pause()
break;
case 'completed': // 播放至结尾状态, 可调用play方法进入playing状态,调用stop方法进入stopped状态
console.info('AVPlayer state completed called.');
this.setPlayState()
avPlayer.stop(); //调用播放结束接口
break;
case 'stopped': // 停止状态, 可调用prepared/playing/paused/completed状态调用stop方法进入此状态
//此状态只保留属性,但会释放内存资源
//可调用prepared重新准备
//可调用reset重置
//可调用release彻底销毁
console.info('AVPlayer state stopped called.');
this.setPlayState()
avPlayer.reset(); // 调用reset接口初始化avplayer状态
break;
case 'released': //销毁状态
console.info('AVPlayer state released called.');
this.setPlayState()
avPlayer.reset()
break;
default:
console.info('AVPlayer state unknown called.');
break;
}
});
//监听进度条长度
avPlayer.on('durationUpdate', (data: number) => {
this.audioDuration = data
this.setPlayState()
console.log('durationUpdate: ' + JSON.stringify(this.audioDuration));
})
//监听进度条当前位置
avPlayer.on('timeUpdate', (data: number) => {
this.currTimeInAudio = data
console.log('timeUpdate: ' + JSON.stringify(this.currTimeInAudio));
})
}
//播放和暂停切换
TogglePlayOrPause() {
if (!this.avPlayer) {
return false;
}
if (this.playState === 'playing') {
this.avPlayer!.pause()
return true;
} else if (this.playState === 'paused') {
this.avPlayer!.play()
return true;
}
return false;
}
//暂停播放
pause() {
if (this.avPlayer) {
this.avPlayer.pause()
}
}
//停止播放
stop() {
if (this.avPlayer) {
this.avPlayer.stop()
}
}
//释放avPlayer
release() {
if (this.avPlayer) {
this.avPlayer.release()
}
}
//重置 avplayer 状态
reset() {
if (this.avPlayer) {
this.avPlayer.reset()
}
}
//播放
async play(audioSrc: string, surfaceID?: string | undefined) {
//如果播放状态为playing或者paused,返回true,调用指定方法,直接return;
let res = this.TogglePlayOrPause();
if (res) {
return;
}
//如果avplayer不存在,创建,此时播放状态为 idle: 空闲状态
await this.createAVPlayer()
//设置状态机
this.setAVPlayerCallback(this.avPlayer!, surfaceID);
//设置 音频url,状态自动跳至 initialized
this.avPlayer!.url = audioSrc;
}
}
十二:UI完整代码
import { media } from '@kit.MediaKit'
import { AvPlayerUtil } from './AvPlayerUtil'
@Component
struct AvPlayer_VideoPage {
xcpController: XComponentController = new XComponentController()
@State surfaceID: string | undefined = undefined
private avPlayer: media.AVPlayer | undefined = undefined
build() {
NavDestination() {
Column() {
XComponent({
id: 'player',
type: XComponentType.SURFACE,
controller: this.xcpController,
})
.width('80%')
.height(200)
.onLoad(() => {
this.surfaceID = this.xcpController.getXComponentSurfaceId()
AvPlayerUtil._instance.play('https://media.w3.org/2010/05/sintel/trailer.mp4', this.surfaceID)
})
.onDestroy(() => {
AvPlayerUtil._instance.release()
})
}
.width('100%')
.height('100%')
}
.hideTitleBar(true)
}
}
@Builder
function AvPlayer_VideoPageBuilder() {
AvPlayer_VideoPage()
}
更多关于HarmonyOS 鸿蒙Next中avPlayer播放视频的实战教程也可以访问 https://www.itying.com/category-93-b0.html
7 回复
感谢分享
点赞!
感谢分享
写的真不错,学习到了
在HarmonyOS Next中,avPlayer是视频播放的核心组件。使用步骤如下:
- 创建AvPlayer实例:
let avPlayer = new media.AvPlayer()
- 设置播放源:
- 网络视频:
avPlayer.url = 'http://example.com/video.mp4'
- 本地视频:
avPlayer.fdSrc = {fd:xxx, offset:0, length:xxx}
- 设置监听事件:
avPlayer.on('stateChange', (state) => {})
- 准备并播放:
avPlayer.prepare()
avPlayer.play()
支持播放控制:
pause()
暂停stop()
停止seek()
跳转setVolume()
音量调节
注意:需申请ohos.permission.INTERNET权限(网络播放时),
您的代码实现基本正确,展示了HarmonyOS Next中AVPlayer的完整使用流程。以下是关键点说明:
-
网络权限配置正确,需要在
module.json5
中声明ohos.permission.INTERNET
权限。 -
AVPlayer状态机处理完善,涵盖了所有关键状态:
idle → initialized → prepared → playing
是正常播放流程- 正确处理了
pause/stop/reset/release
等操作
-
视频播放需要特别注意:
- 必须使用XComponent作为视频渲染容器
- 需要在
initialized
状态设置surfaceId
- 示例中正确获取了XComponent的
surfaceId
-
工具类封装合理,提供了完整的播放控制方法。
建议改进点:
- 增加错误处理,特别是网络异常时的重试机制
- 考虑添加缓冲状态监听(
bufferUpdate
事件) - 视频尺寸可能需要根据内容自适应调整
当前实现已能满足基本视频播放需求,代码结构清晰,状态处理完整,是标准的HarmonyOS媒体播放实现方式。