0.常量定义
在视频播放工具类中,大部分使用到的常量都被提前定义。
class CommonConstants {
/**
* Video aspect ratio.
* 视频横纵比
*/
static readonly VIDEO_ASPECT_RATIO: number = 1.78;
/**
* Video detail.
* 视频细节
*/
static readonly VIDEO_DETAIL: string = 'videoDetail';
/**
* Full percent.
* 百分之百
*/
static readonly FULL_PERCENT: string = '100%';
/**
* Idle state of avPlayer.
* avPlayer 的空闲状态
*/
static readonly AV_PLAYER_IDLE_STATE: string = 'idle';
/**
* Initialized state of avPlayer.
* avPlayer 的初始化状态
*/
static readonly AV_PLAYER_INITIALIZED_STATE: string = 'initialized';
/**
* Prepared state of avPlayer.
* avPlayer 的准备状态
*/
static readonly AV_PLAYER_PREPARED_STATE: string = 'prepared';
/**
* Playing state of avPlayer.
* avPlayer 的播放状态
*/
static readonly AV_PLAYER_PLAYING_STATE: string = 'playing';
/**
* Pause state of avPlayer.
*/
static readonly AV_PLAYER_PAUSED_STATE: string = 'paused';
/**
* Completed state of avPlayer.
* avPlayer 的完成状态
*/
static readonly AV_PLAYER_COMPLETED_STATE: string = 'completed';
/**
* Stopped state of avPlayer.
* avPlayer 的停止状态
*/
static readonly AV_PLAYER_STOPPED_STATE: string = 'stopped';
/**
* Release state of avPlayer.
* avPlayer 的发布状态
*/
static readonly AV_PLAYER_RELEASE_STATE: string = 'released';
/**
* Error state of avPlayer.
* avPlayer 的错误状态
*/
static readonly AV_PLAYER_ERROR_STATE: string = 'error';
/**
* 视频组件的hsp包名.
*/
static readonly VIDEO_DETAIL_HSP_NAME: string = 'entry';
/**
* Current time of avPlayer.
* avPlayer的当前时间
*/
static readonly AV_PLAYER_CURRENT_TIME: string = 'currentTime';
/**
* Progress of av player.
* avPlayer的进度
*/
static readonly AV_PLAYER_PROGRESS: string = 'progress';
/**
* Total time of av player.
* avPlayer的总时间
*/
static readonly AV_PLAYER_TOTAL_TIME: string = 'totalTime';
/**
* Update time of av player.
* avPlayer的更新的时间
*/
static readonly AV_PLAYER_UPDATE_TIME: string = 'updateTime';
/**
* Initial time.
* 初始化时间
*/
static readonly INITIAL_TIME: string = '00:00:00';
/**
* One hundred for progress.
* 进度条:100
*/
static readonly PROGRESS_HUNDRED: number = 100;
/**
* One thousand for progress.
* 进度条:1000
*/
static readonly PROGRESS_THOUSAND: number = 1000;
/**
* Product video name.
* 视频名
*/
static readonly PRODUCT_VIDEO_NAME: string = 'product.mp4';
/**
* Second in hour.
* 一小时的秒数
*/
static readonly SECOND_IN_HOUR: number = 3600;
/**
* Second in minute.
* 一分钟的秒数
*/
static readonly SECOND_IN_MINUTE: number = 60;
/**
* colon.
* 冒号
*/
static readonly COLON: string = ':';
/**
* Time prefix.
* 时间前缀
*/
static readonly TIME_PREFIX: string = '0';
/**
* Empty time.
* 空时间
*/
static readonly EMPTY_TIME: string = '00';
/**
* Zero.
* 数字:0
*/
static readonly ZERO: number = 0;
/**
* One.
* 数字:1
*/
static readonly ONE: number = 1;
/**
* Ten.
* 数字:10
*/
static readonly TEN: number = 10;
}
1.需要创建的对象
// 创建mediaKIT中的AVPlayer实体,用于音视频的播放
private avPlayer ?: media.AVPlayer
// 创建一个AVImageGenerator实体,用于获取缩略图
private avImageGenerator ?: media.AVImageGenerator
// 获取当前页面的UIAbility的上下文信息
private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext
// 视频播放的路径
private url: resourceManager.RawFileDescriptor | null = null
private pixel_map : image.PixelMap | undefined = undefined;
private playState: boolean = true
private surfaceId: string = ''
private sliderBegin: number = 0
private startTime: number = 0
private isFullScreen: boolean = false
private updateTime: number = 0
2.私有函数
2.1 报错进行日志输出
private onError: (err: BusinessError) => void = (err: BusinessError) => {
Logger.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`)
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`)
return
}
this.avPlayer.reset()
}
2.2 视频播放时的时间更新
private onTimeUpdateFunction: (updateTime: number) => void = (updateTime: number) => {
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`)
return
}
this.updateTime = updateTime
AppStorage.setOrCreate<string>(CommonConstants.AV_PLAYER_CURRENT_TIME, this.formatTime(updateTime)) // 当前播放时间
AppStorage.setOrCreate<number>(CommonConstants.AV_PLAYER_UPDATE_TIME, updateTime) // 更新的时间
AppStorage.setOrCreate<number>(CommonConstants.AV_PLAYER_PROGRESS,
updateTime / this.avPlayer.duration * CommonConstants.PROGRESS_HUNDRED) // 当前进度
}
2.3 AVPlayer的状态切换
// avPlayer 状态切换
private onStateChange: (state: media.AVPlayerState) => void = async (state: media.AVPlayerState) => {
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`);
return;
}
switch (state) {
case CommonConstants.AV_PLAYER_IDLE_STATE:
this.url = await this.context.createModuleContext(CommonConstants.VIDEO_DETAIL_HSP_NAME).resourceManager
.getRawFd(CommonConstants.PRODUCT_VIDEO_NAME);
this.avPlayer.fdSrc = this.url;
Logger.info('AVPlayer state idle called.');
break;
case CommonConstants.AV_PLAYER_INITIALIZED_STATE:
Logger.info('AVPlayer initialized called.');
this.avPlayer.surfaceId = this.surfaceId;
this.avPlayer.prepare().then(() => {
Logger.info('AVPlayer prepare succeeded.');
}, (err: BusinessError) => {
Logger.error(`Invoke prepare failed, code is ${err.code}, message is ${err.message}`);
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`);
return;
}
this.avPlayer.reset();
});
break;
case CommonConstants.AV_PLAYER_PREPARED_STATE:
this.avPlayer.videoScaleType = media.VideoScaleType.VIDEO_SCALE_TYPE_FIT;
Logger.info('AVPlayer state prepared called.');
this.seekToStart();
this.avPlayer.play();
AppStorage.setOrCreate<string>(CommonConstants.AV_PLAYER_TOTAL_TIME, this.formatTime(this.avPlayer.duration));
break;
case CommonConstants.AV_PLAYER_PLAYING_STATE:
Logger.info('AVPlayer state playing called.');
this.playState = true;
if (this.isFullScreen) {
AppStorage.setOrCreate<boolean>('fullScreenPlayState', this.playState);
}
this.seekToStart();
break;
case CommonConstants.AV_PLAYER_PAUSED_STATE:
Logger.info('AVPlayer state paused called.');
this.playState = false;
if (this.isFullScreen) {
AppStorage.setOrCreate<boolean>('fullScreenPlayState', this.playState);
}
this.seekToStart();
break;
case CommonConstants.AV_PLAYER_COMPLETED_STATE:
Logger.info('AVPlayer state completed called.');
this.playState = false;
if (this.isFullScreen) {
AppStorage.setOrCreate<boolean>('fullScreenPlayState', this.playState);
}
this.avPlayer.stop();
break;
case CommonConstants.AV_PLAYER_STOPPED_STATE:
Logger.info('AVPlayer state stopped called.');
break;
case CommonConstants.AV_PLAYER_RELEASE_STATE:
Logger.info('AVPlayer state released called.');
break;
case CommonConstants.AV_PLAYER_ERROR_STATE:
Logger.error('AVPlayer state error called.');
break;
default:
Logger.info('AVPlayer state unknown called.');
break;
}
}
3. 暴露的函数,可供外部使用
3.1 创建AVPlayer对象
async createAvPlayer(surfaceId: string, isFullScreen: boolean) {
this.isFullScreen = isFullScreen
if (this.avPlayer === undefined || this.avPlayer.state === CommonConstants.AV_PLAYER_RELEASE_STATE) {
this.avPlayer = await media.createAVPlayer()
this.avImageGenerator = await media.createAVImageGenerator()
this.surfaceId = surfaceId
Logger.info('Created AvPlayer successfully.');
this.url = await this.context.createModuleContext(CommonConstants.VIDEO_DETAIL_HSP_NAME).resourceManager
.getRawFd(CommonConstants.PRODUCT_VIDEO_NAME);
this.avPlayer.fdSrc = this.url;
this.avImageGenerator.fdSrc = this.url
this.setAVPlayerCallback();
} else {
Logger.info(`AvPlayer has been created`);
}
}
3.2 获取某一时刻的视频图片
async getPixelImage(time: number){
let queryOption = media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC
let param: media.PixelMapParams = {
width : 300,
height : 300
}
this.pixel_map = await this.avImageGenerator?.fetchFrameByTime(time,queryOption,param)
return this.pixel_map
}
3.3 获取当前视频播放的时间
getCurrentTime(){
return this.updateTime
}
3.4 设置AVPlayer回调
setAVPlayerCallback(): void {
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`);
return;
}
this.avPlayer.on('error', this.onError);
this.onTimeUpdate();
this.setStateChange();
}
3.5 AVPlayer的时间更新开关
onTimeUpdate(): void {
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`);
return;
}
this.avPlayer.on('timeUpdate', this.onTimeUpdateFunction);
}
offTimeUpdate(): void {
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`);
return;
}
try {
this.avPlayer.off('timeUpdate');
} catch (exception) {
Logger.error('Failed to unregister callback. Code: ' + JSON.stringify(exception));
}
}
3.6 获取视频的总时长
getDuration(): number|undefined{
return this.avPlayer?.duration
}
3.7 设置状态改变
setStateChange(): void {
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`);
return;
}
this.avPlayer.on('stateChange', this.onStateChange)
}
3.8 设置开始时间
setStartTime(startTime: number): void {
this.startTime = startTime;
}
3.9 从开始位置进行播放
seekToStart(): void {
if (this.startTime != 0 && this.avPlayer !== undefined) {
this.avPlayer.seek(this.startTime, media.SeekMode.SEEK_PREV_SYNC);
this.startTime = 0;
} else {
Logger.info(`Video is played from the beginning`);
}
}
3.10 释放资源
release(): void {
if (this.avPlayer !== undefined && this.avPlayer.state !== CommonConstants.AV_PLAYER_RELEASE_STATE) {
try {
this.avPlayer.off('error');
this.avPlayer.off('stateChange');
} catch (exception) {
Logger.error('Failed to unregister callback. Code: ' + JSON.stringify(exception));
}
this.avImageGenerator?.release()
this.avPlayer.release();
} else {
Logger.info(`AvPlayer release failed`);
}
}
3.11 设置视频播放的位置
sliderChange(value: number, mode: SliderChangeMode): void {
let seekType: media.SeekMode = value > this.sliderBegin ? media.SeekMode.SEEK_PREV_SYNC :
media.SeekMode.SEEK_NEXT_SYNC;
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`);
return;
}
switch (mode) {
case SliderChangeMode.Begin:
Logger.info(`AvPlayer SliderChangeMode Begin`);
this.sliderBegin = value;
this.avPlayer.pause();
break;
case SliderChangeMode.Moving:
Logger.info(`AvPlayer SliderChangeMode Moving`);
this.avPlayer.seek(value / CommonConstants.PROGRESS_HUNDRED * this.avPlayer.duration, seekType);
break;
case SliderChangeMode.End:
Logger.info(`AvPlayer SliderChangeMode End`);
this.avPlayer.play();
break;
case SliderChangeMode.Click:
Logger.info(`AvPlayer SliderChangeMode Click`);
this.avPlayer.seek(this.sliderBegin / CommonConstants.PROGRESS_HUNDRED * this.avPlayer.duration, seekType);
break;
default:
break;
}
}
3.12 视频播放状态修改(播放/暂停)
playerStateControl(): void {
if (this.avPlayer === undefined) {
Logger.error(`AvPlayer is undefined`);
return;
}
if (this.avPlayer.state === CommonConstants.AV_PLAYER_STOPPED_STATE) {
this.avPlayer.prepare();
return;
}
if (!this.playState) {
this.avPlayer.play();
} else {
this.avPlayer.pause();
}
}
3.13 视频播放
play(): void {
if (this.avPlayer !== undefined && !this.playState) {
this.avPlayer.play();
} else {
Logger.info(`AvPlayer play failed`);
}
}
3.14 视频暂停
pause(): void {
if (this.avPlayer !== undefined && this.playState) {
this.avPlayer.pause();
} else {
Logger.info(`AvPlayer pause failed`);
}
}
3.15 设置视频源路径
setUrl(url: resourceManager.RawFileDescriptor | null) {
this.url = url
}
3.16 时间格式化
formatTime(duration: number): string {
let totalSecond: number = Math.round(duration / CommonConstants.PROGRESS_THOUSAND);
let hourNum: number = Math.floor(totalSecond / CommonConstants.SECOND_IN_HOUR);
let minNum: number = Math.floor((totalSecond % CommonConstants.SECOND_IN_HOUR) / CommonConstants.SECOND_IN_MINUTE);
let secNum: number = (totalSecond % CommonConstants.SECOND_IN_HOUR) % CommonConstants.SECOND_IN_MINUTE;
return this.formatUnitTime(hourNum) + CommonConstants.COLON + this.formatUnitTime(minNum) + CommonConstants.COLON +
this.formatUnitTime(secNum);
}
formatUnitTime(time: number): string {
if (time >= CommonConstants.ONE && time < CommonConstants.TEN) {
let zero: string = CommonConstants.TIME_PREFIX;
return zero.concat(time.toString());
} else if (time >= CommonConstants.ZERO && time < CommonConstants.ONE) {
return CommonConstants.EMPTY_TIME;
}
return time.toString();
}
4.如何使用
// TODO 待更新。。。。。