HarmonyOS开发实战:音视频播放-AVPlayer

161 篇文章 0 订阅
151 篇文章 0 订阅
1 场景描述

示例场景:AVPlayer播放视频ArkTS实现,创建AVPlayer,设置播放资源和窗口,设置播放参数,播放控制(播放/暂停/跳转),重置,销毁资源,播放完成后切换视频。

2 方案描述

AVPlayer:功能较完善的音视频播放ArkTS API,集成了流媒体和本地资源解析,媒体资源解封装,视频解码和渲染功能,适用于对媒体资源进行端到端播放的场景,可直接播放mp4、mkv等格式的视频文件。本示例就是使用avplayer进行视频播放的实现,功能包括多种方式播放视频,以及对于视频播放的控制。

具体实现步骤可分为Step1: 调用createAVPlayer()创建AVPlayer实例。Step2: 设置业务需要的监听事件,搭配全流程场景使用。Step3: 设置窗口:获取并设置属性SurfaceID,用于设置显示画面。应用需要从XComponent组件获取surfaceID。同时设置load事件,应该改成并在onload事件回调中完成设置播放资源的操作Step4: 注册avplayer回调函数Step5: 调用相关接口实现播放play(),暂停pause(),跳转seek()等操作。

2.1 创建AVPlayer实例

调用createAVPlayer()创建AVPlayer实例

1.通过url设置网络地址来实现播放


async avPlayerLiveDemo() {

// 创建avPlayer实例对象

let avPlayer: media.AVPlayer = await media.createAVPlayer();

// 创建状态机变化回调函数

this.setAVPlayerCallback(avPlayer);

avPlayer.url = 'https://xxxx; // 播放网络视频

}

}

2.使用fs文件系统打开沙箱地址获取媒体文件地址并通过dataSrc属性进行播放


async avPlayerLiveDemo() {

// 创建avPlayer实例对象

let avPlayer: media.AVPlayer = await media.createAVPlayer();

// 创建状态机变化回调函数

this.setAVPlayerCallback(avPlayer);

avPlayer.url = 'https://sns-video-bd.xhscdn.com/stream/110/258/01e602cadc11542d010370038e7ae8b418_258.mp4'; // 播放网络视频

}

}async avPlayerDataSrcDemo

// 创建avPlayer实例对象

let avPlayer: media.AVPlayer = await media.createAVPlayer();

// 创建状态机变化回调函数

this.setAVPlayerCallback(avPlayer);

// dataSrc播放模式的的播放源地址,当播放为Seek模式时fileSize为播放文件的具体大小,下面会对fileSize赋值

let src: media.AVDataSrcDescriptor = {

fileSize: -1,

callback: (buf: ArrayBuffer, length: number, pos: number | undefined) => {

let num = 0;

if (buf == undefined || length == undefined || pos == undefined) {

return -1;

}

num = fs.readSync(this.fd, buf, { offset: pos, length: length });

if (num > 0 && (this.fileSize >= pos)) {

return num;

}

return -1;

}

}

let context = getContext(this) as common.UIAbilityContext;

// 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例

let pathDir = context.filesDir;

let path = pathDir + '/H264_AAC.mp4';

await fs.open(path).then((file: fs.File) => {

this.fd = file.fd;

})

// 获取播放文件的大小

this.fileSize = fs.statSync(path).size;

src.fileSize = this.fileSize;

avPlayer.dataSrc = src;

}

}

3.使用资源管理接口获取打包在HAP内的媒体资源文件并通过fdSrc属性进行播放


async avPlayerFdSrcDemo() {

// 创建avPlayer实例对象

this.player = await media.createAVPlayer();

// 创建状态机变化回调函数

this.setAVPlayerCallback(this.player);

// 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址

// 返回类型为{fd,offset,length},fd为HAP包fd地址,offset为媒体资源偏移量,length为播放长度

let context = getContext(this) as common.UIAbilityContext;

let fileDescriptor = await context.resourceManager.getRawFd('1234.mp4');

let avFileDescriptor: media.AVFileDescriptor =

{ fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };

// 为fdSrc赋值触发initialized状态机上报

this.player.fdSrc = avFileDescriptor;

}

4.使用fs文件系统打开沙箱地址获取媒体文件地址并通过url属性进行播放


async avPlayerUrlDemo() {

// 创建avPlayer实例对象

this.player = await media.createAVPlayer();

this.setAVPlayerCallback(this.player);

let fdPath = 'fd://';

let context = getContext(this) as common.UIAbilityContext;

// 通过UIAbilityContext获取沙箱地址filesDir,以Stage模型为例

let pathDir = context.filesDir;

console.info(pathDir)

let path = pathDir + '/1234.mp4';

// 打开相应的资源文件地址获取fd,并为url赋值触发initialized状态机上报

let file = await fs.open(path);

fdPath = fdPath + '' + file.fd;

this.player.url = fdPath;

}

2.3 设置业务需要的监听事件

支持的监听事件包括:

事件类型

说明

stateChange

必要事件,监听播放器的state属性改变。

error

必要事件,监听播放器的错误信息。

durationUpdate

用于进度条,监听进度条长度,刷新资源时长。

timeUpdate

用于进度条,监听进度条当前位置,刷新当前时间。

seekDone

响应API调用,监听seek()请求完成情况。当使用seek()跳转到指定播放位置后,如果seek操作成功,将上报该事件。

speedDone

响应API调用,监听setSpeed()请求完成情况。当使用setSpeed()设置播放倍速后,如果setSpeed操作成功,将上报该事件。

volumeChange

响应API调用,监听setVolume()请求完成情况。当使用setVolume()调节播放音量后,如果setVolume操作成功,将上报该事件。

bitrateDone

响应API调用,用于HLS协议流,监听setBitrate()请求完成情况。当使用setBitrate()指定播放比特率后,如果setBitrate操作成功,将上报该事件。

availableBitrates

用于HLS协议流,监听HLS资源的可选bitrates,用于setBitrate()。

bufferingUpdate

用于网络播放,监听网络播放缓冲信息。

startRenderFrame

用于视频播放,监听视频播放首帧渲染时间。当AVPlayer首次起播进入playing状态后,等到首帧视频画面被渲染到显示画面时,将上报该事件。应用通常可以利用此事件上报,进行视频封面移除,达成封面与视频画面的顺利衔接。

videoSizeChange

用于视频播放,监听视频播放的宽高信息,可用于调整窗口大小、比例。

audioInterrupt

监听音频焦点切换信息,搭配属性audioInterruptMode使用。如果当前设备存在多个媒体正在播放,音频焦点被切换(即播放其他媒体如通话等)时将上报该事件,应用可以及时处理。


avPlayer.on('speedDone', (number: Number) => this.speedDone(number));



avPlayer.on('seekDone', (number: Number) => this.seekDone(number));

2.4 设置窗口

XComponent的类型设置为SURFACE,在type设置为为SURFACE时可以支持Load事件,Load事件的作用是插件加载完成时回调事件,在回调中设置好需要播放的资源。


build()

Column() {

XComponent({

id: 'AVPlayer',

type: XComponentType.SURFACE,

controller: this.xComponentController

})

.onLoad (()=> {

this.surfaceID = this.xComponentController.getXComponentSurfaceId()

this.xComponentContext = this.xComponentController.getXComponentContext() as Record<string, () => void>

})

2.5 注册avplayer回调函数

  • idle:闲置状态,AVPlayer刚被创建createAVPlayer()或者调用了reset()方法之后,进入Idle状态。首次创建createAVPlayer(),所有属性都为默认值。 调用reset()方法,url 或 fdSrc或dataSrc属性及loop属性会被重置,其他用户设置的属性将被保留。

  • initialized:资源初始化,在Idle 状态设置 url或 fdSrc属性,AVPlayer会进入initialized状态,此时可以配置窗口、音频等静态属性。

  • prepared:已准备状态,在initialized状态调用prepare()方法,AVPlayer会进入prepared状态,此时播放引擎的资源已准备就绪。

  • playing:正在播放状态,在prepared/paused/completed状态调用play()方法,AVPlayer会进入playing状态。

  • paused:暂停状态,在playing状态调用pause方法,AVPlayer会进入paused状态。

  • completed:播放至结尾状态,当媒体资源播放至结尾时,如果用户未设置循环播放,AVPlayer会进入completed状态。

  • stopped:停止状态,在prepared/playing/paused/completed状态调用stop()方法,AVPlayer会进入stopped状态,此时播放引擎只会保留属性,但会释放内存资源,可以调用prepare()重新准备,也可以调用reset()重置,或者调用release()彻底销毁。

  • released:销毁状态,销毁与当前AVPlayer关联的播放引擎,无法再进行状态转换,调用release()方法后,会进入released状态,结束流程。


private setAVPlayerCallback(avPlayer: media.AVPlayer) {

if (this.player == null) {

return;

}

// // 响应API调用,监听seek()请求完成情况。

avPlayer.on('speedDone', (number: Number) => this.speedDone(number));

avPlayer.on('seekDone', (number: Number) => this.seekDone(number));

// 状态机变化回调函数

avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {

switch (state) {

case 'idle': // 成功调用reset接口后触发该状态机上报

console.info('AVPlayer state idle called.');

break;

case 'initialized': // avplayer 设置播放源后触发该状态上报

console.info('AVPlayer state initialized called.');

avPlayer.surfaceId = this.surfaceID; // 设置显示画面,当播放的资源为纯音频时无需设置

avPlayer.prepare();

break;

case 'prepared': // prepare调用成功后上报该状态机

console.info('AVPlayer state prepared called.');

avPlayer.play(); // 调用播放接口开始播放

break;

case 'playing': // play成功调用后触发该状态机上报

console.info('AVPlayer state playing called.');

break;

case 'paused': // pause成功调用后触发该状态机上报

console.info('AVPlayer state paused called.');

break;

case 'completed': // 播放结束后触发该状态机上报

console.info('AVPlayer state completed called.');

avPlayer.stop(); //调用播放结束接口

break;

case 'stopped': // stop接口成功调用后触发该状态机上报

console.info('AVPlayer state stopped called.');

avPlayer.release();

break;

case 'released':

console.info('AVPlayer state released called.');

break;

default:

console.info('AVPlayer state unknown called.');

break;

}

})

}

2.6 播放控制

1.暂停和播放


Button('start')

.onClick(() => {

this.avPlayerDataSrcNOSeekDemo()

})

.margin({right:12})

.margin({top:5})

.width(150)


Button('paused')

.onClick(() => {

this.player?.pause();

})

.margin({right:12})

.margin({top:5})

.width(150)



Button('player')

.onClick(() => {

this.player?.play();

})

.margin({right:12})

.margin({top:5})

.width(150)

2.停止播放,销毁


Button('stop')

.onClick(() => {

this.player?.stop();

})

.margin({right:12})

3.重置切换视频


Button('reset')

.onClick(() => {

this.player?.reset();

})

.margin({right:12})

4.倍速这里设置的是二倍速播放这里可以通过设置PlaybackSpeed的枚举,来实现不同速率的播放。这里设置的是SPEED_FORWARD_2_00_X,二倍速。


Button('speed')

.onClick(() => {

this.player?.setSpeed(media.PlaybackSpeed.SPEED_FORWARD_2_00_X);

})

.margin({right:12})

5.跳转seek跳转到指定播放位置,只能在prepared/playing/paused/completed状态调用,跳转时间节点的单位是ms,通过设置枚举值控制跳转的模式。

名称

说明

SEEK_NEXT_SYNC

0

表示跳转到指定时间点的下一个关键帧,建议向后快进的时候用这个枚举值。

SEEK_PREV_SYNC

1

表示跳转到指定时间点的上一个关键帧,建议向前快进的时候用这个枚举值。

SEEK_CLOSEST

2

表示跳转到指定时间点的最接近的帧,建议精准查找的时候用这个枚举值。

Button('seek')

.onClick(() => {

this.player?.seek(6000,0);

})

.margin({right:12}

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?但是又不知道从哪里下手,而且学习时频繁踩坑,最终浪费大量时间。所以本人整理了一些比较合适的鸿蒙(HarmonyOS NEXT)学习路径和一些资料的整理供小伙伴学习

 →纯血鸿蒙Next全套最新学习资料

希望这一份鸿蒙学习资料能够给大家带来帮助

                             
                                     

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用AVAudioRecorder和AVPlayer来实现在iOS设备上边录音边播放。具体步骤如下: 1. 配置AVAudioSession,设置播放和录音的类别和模式: ```swift let session = AVAudioSession.sharedInstance() try? session.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetoothA2DP]) try? session.setActive(true) ``` 2. 创建AVAudioRecorder实例,设置录音参数和文件路径: ```swift let recordSettings = [ AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 44100, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue ] let audioURL = URL(fileURLWithPath: NSTemporaryDirectory() + "recording.m4a") let audioRecorder = try? AVAudioRecorder(url: audioURL, settings: recordSettings) audioRecorder?.prepareToRecord() audioRecorder?.record() ``` 3. 创建AVPlayer实例,设置播放URL和缓存: ```swift let audioURL = URL(string: "http://example.com/audio.mp3")! let playerItem = AVPlayerItem(url: audioURL) let player = AVPlayer(playerItem: playerItem) player.automaticallyWaitsToMinimizeStalling = false player.play() ``` 4. 在AVPlayer的代理方法中,检查缓存是否够用,如果不够用就暂停AVPlayer,等待缓存: ```swift func player(_ player: AVPlayer, didOutputCueMarkers markers: [AVMetadataItem], at time: CMTime) { let currentTime = player.currentTime() let bufferDuration = CMTimeGetSeconds(player.currentItem?.loadedTimeRanges.first?.timeRange.duration ?? CMTime.zero) let playbackDuration = CMTimeGetSeconds(currentTime) if bufferDuration - playbackDuration < 5 { player.pause() } else { player.play() } } ``` 这样就可以在iOS设备上边录音边播放了。注意,由于网络传输和设备性能的限制,可能会出现播放卡顿或录音失真的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值