HarmonyOS鸿蒙Next中请问你们的ijkplayer组件里timeUpdate怎么写,需要检测到秒的回调
HarmonyOS鸿蒙Next中请问你们的ijkplayer组件里timeUpdate怎么写,需要检测到秒的回调 最近用了ijkplayer播放器,需要做一个秒的回调,然后在做一个进度条,目前有一个,就是不知道它回调的都代表什么
setOnInfoListener:设置播放器的各种状态回调监听
开发者您好,如果您这边想实现进度条逻辑,可以使用ijkplayer提供的接口:
// 获取当前播放位置
let position = this.mIjkMediaPlayer.getCurrentPosition();
// 获取视频时长
let duration = this.mIjkMediaPlayer.getDuration();
通过定时任务定时刷新当前视频播放进度:
this.updateProgressTimer = setInterval(() => {
if (!this..mDestroyPage) {
that.setProgress();
}
}, 1000);
private setProgress() {
let position = this.mIjkMediaPlayer.getCurrentPosition();
let duration = this.mIjkMediaPlayer.getDuration();
let pos = 0;
if (duration > 0) {
this.slideEnable = true;
let curPercent = position / duration;
pos = curPercent * 100;
if (pos > this.PROGRESS_MAX_VALUE) {
this.progressValue = this.PROGRESS_MAX_VALUE;
} else {
this.progressValue = pos;
}
}
this.totalTime = this.stringForTime(duration);
if (position > duration) {
position = duration;
}
this.isCurrentTime = true;
this.currentTime = this.stringForTime(position);
this.isCurrentTime = false;
}
完整示例代码如下:
import { Callback } from '[@ohos](/user/ohos).base';
import { IjkMediaPlayer, InterruptEvent, InterruptHintType } from '[@ohos](/user/ohos)/ijkplayer';
import { OnVideoSizeChangedListener } from '[@ohos](/user/ohos)/ijkplayer';
import { OnCompletionListener } from '[@ohos](/user/ohos)/ijkplayer';
import { OnErrorListener } from '[@ohos](/user/ohos)/ijkplayer';
import { OnInfoListener } from '[@ohos](/user/ohos)/ijkplayer';
import { OnSeekCompleteListener } from '[@ohos](/user/ohos)/ijkplayer';
import { LogUtils } from '[@ohos](/user/ohos)/ijkplayer';
import { window } from '[@kit](/user/kit).ArkUI';
import { BusinessError } from '[@kit](/user/kit).BasicServicesKit';
export enum PlayStatus {
INIT = 0,
PAUSE = 1,
PLAY = 2,
};
[@Entry](/user/Entry)
[@Component](/user/Component)
struct PageDemo {
[@State](/user/State) progressValue: number = 0;
[@State](/user/State) currentTime: string = '00:00';
[@State](/user/State) totalTime: string = '00:00';
[@State](/user/State) replayVisible: Visibility = Visibility.None;
[@State](/user/State) slideEnable: boolean = false;
private mContext: object | undefined = undefined;
private mFirst: boolean = true;
private mDestroyPage: boolean = false;
private playSpeed: string = '1f';
[@State](/user/State) volume: number = 1.0;
private oldSeconds: number = 0;
private isSeekTo: boolean = false;
private isCurrentTime: boolean = false;
[@State](/user/State) videoWidth: string = '100%';
private initAspectRatio: number = 1;
[@State](/user/State) videoAspectRatio: number = this.initAspectRatio;
private last: number = 0;
[@State](/user/State) loadingVisible: Visibility = Visibility.None;
private videoParentAspectRatio: number = this.initAspectRatio;
private mIjkMediaPlayer = IjkMediaPlayer.getInstance();
private controlPlayStatus = PlayStatus.INIT;
private PROGRESS_MAX_VALUE: number = 100;
private updateProgressTimer: number = 0;
private curIndex: number = 0;
// 此处设置rtsp播放源链接即可
private videoUrls: string[] = [
'https://1252866558.vod2.myqcloud.com/9eadadb7vodtransgzp1252866558/2f7e1372243791580925650614/v.f1425023.mp4',
'https://1251542705.vod2.myqcloud.com/4a8d9c67vodtransgzp1251542705/203109c63270835013529449619/v.f1419907.mp4'];
private videoUrl = this.videoUrls[0]
[@State](/user/State) isRecord: boolean = false
controller: TextClockController = new TextClockController();
[@State](/user/State) light: boolean = true;
aboutToAppear() {
let event: Callback<InterruptEvent> = (event) => {
LogUtils.getInstance().LOGI(`event: ${JSON.stringify(event)}`);
if (event.hintType === InterruptHintType.INTERRUPT_HINT_PAUSE) {
this.pause();
} else if (event.hintType === InterruptHintType.INTERRUPT_HINT_RESUME) {
this.startPlayOrResumePlay();
} else if (event.hintType === InterruptHintType.INTERRUPT_HINT_STOP) {
this.stop();
}
};
this.mIjkMediaPlayer.on('audioInterrupt', event);
this.controller.start()
}
aboutToDisappear() {
// 退出
this.mDestroyPage = true;
this.mIjkMediaPlayer.setScreenOnWhilePlaying(false);
if (this.controlPlayStatus !== PlayStatus.INIT) {
this.stop();
}
this.mIjkMediaPlayer.off('audioInterrupt');
this.controller.stop()
}
onPageShow() {
// 开始播放
if (this.mContext && !this.mFirst) {
this.startPlayOrResumePlay();
}
}
onPageHide() {
// 暂停播放
LogUtils.getInstance().LOGI('onPageHide-->pause');
this.pause();
}
xcomponentController: XComponentController = new XComponentController();
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Auto, justifyContent: FlexAlign.Start }) {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text('ijkplayer播放器').fontSize('30px').fontColor(Color.White).margin('10px').fontWeight(FontWeight.Bold)
}.height('100px').width('100%').backgroundColor(Color.Black)
Divider().vertical(false).strokeWidth('20px').color(Color.White).lineCap(LineCapStyle.Round)
Stack({ alignContent: Alignment.Center }) {
Column() {
XComponent({
id: 'xcomponentId',
type: 'surface',
libraryname: 'ijkplayer_napi'
}).onLoad((event?: object) => {
if (!!event) {
this.initDelayPlay(event);
}
})
.onDestroy(() => {
})
.width('100%')
.width(this.videoWidth)
.aspectRatio(this.videoAspectRatio)
}.aspectRatio(this.videoAspectRatio)
// 此处添加网络加载loading效果
Image($r('app.media.startIcon'))
.objectFit(ImageFit.Auto)
.width('120px')
.height('120px')
.visibility(this.replayVisible)
.border({ width: 0 })
.borderStyle(BorderStyle.Dashed)
.onClick(() => {
this.startPlayOrResumePlay();
})
// 视频播放完成后重新播放
Image($r('app.media.startIcon'))
.objectFit(ImageFit.Auto)
.width('120px')
.height('120px')
.visibility(this.loadingVisible)
.border({ width: 0 })
.borderStyle(BorderStyle.Dashed)
}.width('100%').backgroundColor('#000000').clip(true)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
Text(this.currentTime).width('100px').fontSize('20px').margin('20px');
Slider({
value: this.progressValue,
min: 0,
max: this.PROGRESS_MAX_VALUE,
step: 1,
style: SliderStyle.OutSet
})
.width('600px')
.blockColor(Color.Blue)
.trackColor(Color.Gray)
.selectedColor(Color.Blue)
.showSteps(true)
.showTips(true)
.enabled(this.slideEnable)
.onChange((value: number, mode: SliderChangeMode) => {
if (mode === 2) {
this.isSeekTo = true;
this.mDestroyPage = false;
LogUtils.getInstance().LOGI('slider-->seekValue start:' + value);
let seekValue = value * (this.mIjkMediaPlayer.getDuration() / 100);
this.seekTo(seekValue + '');
this.setProgress();
LogUtils.getInstance().LOGI('slider-->seekValue end:' + seekValue);
this.isSeekTo = false;
}
});
Text(this.totalTime).width('100px').fontSize('20px').margin('10px');
}
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
Button('播放')
.onClick(() => {
this.startPlayOrResumePlay();
}).width('400px').height('80px').margin('15px');
Button('暂停')
.onClick(() => {
this.pause();
}).width('400px').height('80px').margin('15px');
Button('切换')
.onClick(() => {
this.playNext();
}).width('400px').height('80px').margin('15px');
Button('切换常亮').onClick(() => {
this.light = !this.light
console.info('testTag this.light:' + this.light)
this.mIjkMediaPlayer.setScreenOnWhilePlaying(this.light)
})
.width('400px').height('80px').margin('15px');
}
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
Button('1倍速')
.onClick(() => {
if (!this.debounce()) {
return;
}
this.playSpeed = '1f';
this.mIjkMediaPlayer.setSpeed('1f');
})
.width('400px')
.height('80px')
.margin('15px')
Button('1.5倍速')
.onClick(() => {
window.getLastWindow(this.getUIContext().getHostContext()).then((topWindow) => {
const item: window.Window = topWindow;
item.setWindowSystemBarEnable([])
console.info(`Succeeded in obtaining the top window. Window id: ${topWindow.getWindowProperties().id}`);
}).catch((err: BusinessError) => {
console.error(`Failed to obtain the top window. Cause code: ${err.code}, message: ${err.message}`);
});
if (!this.debounce()) {
return;
}
this.playSpeed = '1.5f';
this.mIjkMediaPlayer.setSpeed('1.5f');
})
.width('400px')
.height('80px')
.margin('15px')
Button('切换视频并2 倍速')
.onClick(() => {
this.playSpeed = '2f';
this.mIjkMediaPlayer.setSpeed('2f');
})
.width('400px')
.height('80px')
.margin('15px')
}
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
Text('视频音量').width('120px').fontSize('30px').margin('15px')
Slider({
value: this.volume,
min: 0.0,
max: 1.0,
step: 0.1,
style: SliderStyle.OutSet
})
.width('600px')
.blockColor(Color.Blue)
.trackColor(Color.Gray)
.selectedColor(Color.Blue)
.showSteps(true)
.showTips(true)
.onChange((value: number, mode: SliderChangeMode) => {
if (mode === SliderChangeMode.End) {
this.volume = value;
this.mIjkMediaPlayer.setVolume(this.volume.toString(), this.volume.toString());
}
})
}
}
}
// initDelayPlay
private initDelayPlay(context: object) {
this.mContext = context;
let that = this;
setTimeout(() => {
that.startPlayOrResumePlay();
that.mFirst = false;
}, 300);
}
// startPlayOrResumePlay
private startPlayOrResumePlay() {
this.mDestroyPage = false;
LogUtils.getInstance().LOGI('startPlayOrResumePlay start this.controlPlayStatus:' + this.controlPlayStatus);
if (this.controlPlayStatus === PlayStatus.INIT) {
this.stopProgressTask();
this.startProgressTask();
this.play(this.videoUrl.toString());
}
if (this.controlPlayStatus === PlayStatus.PAUSE) {
this.mIjkMediaPlayer.start();
this.setProgress();
}
}
// completionNum
private completionNum(num: number): string | number {
if (num < 10) {
return '0' + num;
} else {
return num;
}
}
// stringForTime
private stringForTime(timeMs: number): string {
let totalSeconds: number | string = (timeMs / 1000);
let newSeconds: number | string = totalSeconds % 60;
let minutes: number | string = (totalSeconds / 60) % 60;
let hours: number | string = totalSeconds / 3600;
hours = this.completionNum(Math.floor(Math.floor(hours * 100) / 100));
minutes = this.completionNum(Math.floor(Math.floor(minutes * 100) / 100));
newSeconds = Math.floor(Math.floor(newSeconds * 100) / 100);
if (this.isCurrentTime) {
if (this.oldSeconds < newSeconds || newSeconds === 0 || this.isSeekTo) {
this.oldSeconds = newSeconds;
} else {
newSeconds = this.oldSeconds;
}
}
newSeconds = this.completionNum(newSeconds);
if (hours > 0) {
return hours + ':' + minutes + ':' + newSeconds;
} else {
return minutes + ':' + newSeconds;
}
}
// setProgress
private setProgress() {
let position = this.mIjkMediaPlayer.getCurrentPosition();
let duration = this.mIjkMediaPlayer.getDuration();
let pos = 0;
if (duration > 0) {
this.slideEnable = true;
let curPercent = position / duration;
pos = curPercent * 100;
if (pos > this.PROGRESS_MAX_VALUE) {
this.progressValue = this.PROGRESS_MAX_VALUE;
} else {
this.progressValue = pos;
}
}
this.totalTime = this.stringForTime(duration);
if (position > duration) {
position = duration;
}
this.isCurrentTime = true;
this.currentTime = this.stringForTime(position);
this.isCurrentTime = false;
}
// startProgressTask
private startProgressTask() {
let that = this;
this.updateProgressTimer = setInterval(() => {
if (!that.mDestroyPage) {
that.setProgress();
}
}, 1000);
}
// stopProgressTask
private stopProgressTask() {
clearInterval(this.updateProgressTimer);
}
private play(url: string) {
let that = this;
// 设置XComponent回调的context
if (!!this.mContext) {
this.mIjkMediaPlayer.setContext(this.mContext, 'xcomponentId');
}
if (this.controlPlayStatus === PlayStatus.INIT) {
this.mIjkMediaPlayer.reset();
}
this.controlPlayStatus = PlayStatus.PLAY;
// 设置debug模式
this.mIjkMediaPlayer.setDebug(true);
// 初始化配置
this.mIjkMediaPlayer.native_setup();
// 初始化配置后需要重新设置音频流音量,否则音量为默认值1.0
this.mIjkMediaPlayer.setVolume(this.volume.toString(), this.volume.toString());
// 设置视频源
this.mIjkMediaPlayer.setDataSource(url);
// 设置视频源http请求头
let headers = new Map([
["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (xxxx.com)"],
["referer", "xxx.xxx.xxxx.com"]
]);
this.mIjkMediaPlayer.setDataSourceHeader(headers);
this.mIjkMediaPlayer.setScreenOnWhilePlaying(true)
this.mIjkMediaPlayer.setSpeed(this.playSpeed);
let speed = this.mIjkMediaPlayer.getSpeed();
// 是否开启循环播放
let mOnVideoSizeChangedListener: OnVideoSizeChangedListener = {
onVideoSizeChanged: (width: number, height: number, sarNum: number, sarDen: number) => {
if (height === 0) {
return;
}
const va = width / height;
const vpa = that.videoParentAspectRatio;
if (vpa > va) {
this.videoWidth = (width / (height * vpa)) * 100 + '%';
} else {
this.videoWidth = '100%';
}
if (width && height) {
this.videoAspectRatio = width / height;
}
}
};
this.mIjkMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
let mOnCompletionListener: OnCompletionListener = {
onCompletion: () => {
that.currentTime = that.stringForTime(this.mIjkMediaPlayer.getDuration());
that.progressValue = this.PROGRESS_MAX_VALUE;
that.slideEnable = false;
that.stop();
}
};
this.mIjkMediaPlayer.setOnCompletionListener(mOnCompletionListener);
let mOnSeekCompleteListener: OnSeekCompleteListener = {
onSeekComplete: () => {
that.startPlayOrResumePlay();
}
};
this.mIjkMediaPlayer.setOnSeekCompleteListener(mOnSeekCompleteListener);
let mOnInfoListener: OnInfoListener = {
onInfo: (what: number, extra: number) => {
}
};更多关于HarmonyOS鸿蒙Next中请问你们的ijkplayer组件里timeUpdate怎么写,需要检测到秒的回调的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
按照ijkPleyer文档接口编写代码。
这是个三方库嘛?去看一下三方库的md文件或者教程吧:OpenHarmony三方库中心仓 不行就联系一下这个三方组件的作者
是啊,第三方库,你有咩有做过m3u8的播放,有推荐吗
在HarmonyOS鸿蒙Next中,ijkplayer组件的timeUpdate回调可通过监听PlayerEvent.TIME_UPDATE事件实现。使用on('timeUpdate')方法注册监听器,回调函数参数包含当前播放时间(单位:毫秒)。若需检测到秒的回调,可在回调函数内将毫秒转换为秒,并执行相应逻辑。示例代码片段如下:
player.on('timeUpdate', (time) => {
const currentSecond = Math.floor(time / 1000);
// 处理每秒回调逻辑
});
在HarmonyOS Next的ijkplayer中,要实现秒级回调并用于进度条,关键在于正确使用setOnInfoListener和setOnTimeUpdateListener。
对于你的需求,建议优先使用setOnTimeUpdateListener,因为它专门用于时间更新。其回调参数currentPosition(当前播放位置,单位毫秒)和duration(总时长,单位毫秒)正是你构建进度条所需的。
核心实现步骤:
- 设置时间更新监听器:通过
setOnTimeUpdateListener注册回调。 - 在回调中进行秒级判断:在监听器的
onTimeUpdate方法中,将currentPosition(毫秒)转换为秒。你可以通过判断当前秒数是否变化(例如,currentSecond != lastSecond)来触发你的“秒回调”逻辑。 - 更新进度条:在同一回调中,使用
currentPosition和duration计算播放进度百分比((currentPosition / duration) * 100),并据此更新UI进度条。
关于setOnInfoListener:它主要用于播放器状态、缓冲进度等信息的回调(如开始渲染、缓冲开始/结束、解码器信息等),虽然其中也可能包含时间信息,但**setOnTimeUpdateListener是更直接、更专用于时间与进度更新的接口**。
简单代码示意:
// 假设 player 是你的ijkplayer实例
player.setOnTimeUpdateListener({
onTimeUpdate: (currentPosition: number, duration: number) => {
// 1. 秒级回调判断
let currentSec = Math.floor(currentPosition / 1000);
if (currentSec !== this.lastSec) {
this.lastSec = currentSec;
// 在这里执行你需要每秒执行一次的业务逻辑
console.log(`每秒回调: ${currentSec}s`);
}
// 2. 更新进度条
if (duration > 0) {
let progressPercent = (currentPosition / duration) * 100;
// 更新你的UI进度条组件,例如:
// this.uiProgressBar.setValue(progressPercent);
}
}
});
这样,你便可以在一个回调中同时满足“秒回调”和“进度条更新”两个需求。setOnTimeUpdateListener的回调频率通常很高(约每秒多次),通过上述的秒数取整与比较,可以高效地过滤出每秒一次的事件。

