当前位置: 首页 > news >正文

【鸿蒙HarmonyOS Next实战开发】多媒体视频播放-ijkplayer

简介

ijkplayer是OpenHarmony和HarmonyOS环境下可用的一款基于FFmpeg的视频播放器。

演示

下载安装

ohpm install @ohos/ijkplayer

使用说明

   import { IjkMediaPlayer } from "@ohos/ijkplayer";import type { OnPreparedListener } from "@ohos/ijkplayer";import type { OnVideoSizeChangedListener } from "@ohos/ijkplayer";import type { OnCompletionListener } from "@ohos/ijkplayer";import type { OnBufferingUpdateListener } from "@ohos/ijkplayer";import type { OnErrorListener } from "@ohos/ijkplayer";import type { OnInfoListener } from "@ohos/ijkplayer";import type { OnSeekCompleteListener } from "@ohos/ijkplayer";import { LogUtils } from "@ohos/ijkplayer";

在UI中配置XComponent控件

    XComponent({id: 'xcomponentId',type: 'surface',libraryname: 'ijkplayer_napi'}).onLoad((context) => {this.initDelayPlay(context);}).onDestroy(() => {}).width('100%').aspectRatio(this.aspRatio)

播放

    //单例模式let mIjkMediaPlayer = IjkMediaPlayer.getInstance();//多实例模式let mIjkMediaPlayer = new IjkMediaPlayer();// 如果播放视频,调用setContext接口,参数1为XComponent回调的context, 可选参数2为XComponent的id属性值mIjkMediaPlayer.setContext(this.mContext, "xcomponentId");// 如果只播放音频,则调用setAudioId接口,参数为音频对象的id// mIjkMediaPlayer.setAudioId('audioIjkId');// 设置debug模式mIjkMediaPlayer.setDebug(true);// 初始化配置mIjkMediaPlayer.native_setup();// 设置视频源mIjkMediaPlayer.setDataSource(url); // 设置视频源http请求头let headers =  new Map([["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (bbcallen@gmail.com)"],["referer", "https://www.bilibili.com"]]);mIjkMediaPlayer.setDataSourceHeader(headers);// 使用精确寻帧 例如,拖动播放后,会寻找最近的关键帧进行播放,很有可能关键帧的位置不是拖动后的位置,而是较前的位置.可以设置这个参数来解决问题mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", "1");// 预读数据的缓冲区大小mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", "102400");// 停止预读的最小帧数mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", "100");// 启动预加载mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", "1");// 设置无缓冲,这是播放器的缓冲区,有数据就播放mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", "0");// 跳帧处理,放CPU处理较慢时,进行跳帧处理,保证播放流程,画面和声音同步mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", "5");// 最大缓冲cache是3s, 有时候网络波动,会突然在短时间内收到好几秒的数据// 因此需要播放器丢包,才不会累积延时// 这个和第三个参数packet-buffering无关。mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", "3000");// 无限制收流mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", "1");// 屏幕常亮mIjkMediaPlayer.setScreenOnWhilePlaying(true);// 设置超时mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", "10000000");mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "connect_timeout", "10000000");mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "listen_timeout", "10000000");mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "addrinfo_timeout", "10000000");mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_timeout", "10000000");let mOnVideoSizeChangedListener: OnVideoSizeChangedListener = {onVideoSizeChanged(width: number, height: number, sar_num: number, sar_den: number) {that.aspRatio = width / height;LogUtils.getInstance().LOGI("setOnVideoSizeChangedListener-->go:" + width + "," + height + "," + sar_num + "," + sar_den)that.hideLoadIng();}}mIjkMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);let mOnPreparedListener: OnPreparedListener = {onPrepared() {LogUtils.getInstance().LOGI("setOnPreparedListener-->go");}}mIjkMediaPlayer.setOnPreparedListener(mOnPreparedListener);let mOnCompletionListener: OnCompletionListener = {onCompletion() {LogUtils.getInstance().LOGI("OnCompletionListener-->go")that.currentTime = that.stringForTime(mIjkMediaPlayer.getDuration());that.progressValue = PROGRESS_MAX_VALUE;that.stop();}}mIjkMediaPlayer.setOnCompletionListener(mOnCompletionListener);let mOnBufferingUpdateListener: OnBufferingUpdateListener = {onBufferingUpdate(percent: number) {LogUtils.getInstance().LOGI("OnBufferingUpdateListener-->go:" + percent)}}mIjkMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);let mOnSeekCompleteListener: OnSeekCompleteListener = {onSeekComplete() {LogUtils.getInstance().LOGI("OnSeekCompleteListener-->go")that.startPlayOrResumePlay();}}mIjkMediaPlayer.setOnSeekCompleteListener(mOnSeekCompleteListener);let mOnInfoListener: OnInfoListener = {onInfo(what: number, extra: number) {LogUtils.getInstance().LOGI("OnInfoListener-->go:" + what + "===" + extra)}}mIjkMediaPlayer.setOnInfoListener(mOnInfoListener);let mOnErrorListener: OnErrorListener = {onError(what: number, extra: number) {LogUtils.getInstance().LOGI("OnErrorListener-->go:" + what + "===" + extra)that.hideLoadIng();prompt.showToast({message:"亲,视频播放异常,系统开小差咯"});}}mIjkMediaPlayer.setOnErrorListener(mOnErrorListener);mIjkMediaPlayer.setMessageListener();mIjkMediaPlayer.prepareAsync();mIjkMediaPlayer.start();

暂停

   mIjkMediaPlayer.pause();

停止

   mIjkMediaPlayer.stop();

重置

   mIjkMediaPlayer.reset();

释放

   mIjkMediaPlayer.release();

快进、后退

   mIjkMediaPlayer.seekTo(msec);

倍数播放

   mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", "1");mIjkMediaPlayer.setSpeed("2f");

屏幕常亮

   mIjkMediaPlayer.setScreenOnWhilePlaying(true);

循环播放

   mIjkMediaPlayer.setLoopCount(true);

设置音量

   mIjkMediaPlayer.setVolume(leftVolume, rightVolume);

音频焦点监控

   import { InterruptEvent, InterruptHintType } from '@ohos/ijkplayer/src/main/ets/ijkplayer/IjkMediaPlayer';import { Callback } from '@ohos.base';// 音频焦点变化回调处理let event:  Callback<InterruptEvent> = (event) => {console.info(`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();}}// 设置监听音频中断事件mIjkMediaPlayer.on('audioInterrupt', event);// 取消订阅音频中断事件mIjkMediaPlayer.off('audioInterrupt');

开启硬解码

   // 开启h264与h265硬解码ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-all-videos", "1");// 开启h265硬解码ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-hevc", "1");

开启视频录制

    let recordSaveFilePath = getContext(this).cacheDir + "/record.mp4";let result = this.mIjkMediaPlayer.startRecord(recordSaveFilePath);prompt.showToast({message: result ? "开启录制成功" : "开启录制失败"});

获取视频录制状态

    let isRecord = this.mIjkMediaPlayer.isRecord();prompt.showToast({message: isRecord ? "正在录制中" : "录制没有开启哦!"});

停止视频录制

    // 保存相册需要申请权限: ohos.permission.WRITE_IMAGEVIDEOthis.mIjkMediaPlayer.stopRecord().then((result) => {if(!result){prompt.showToast({message: "停止录制失败"});return;}let atManager = abilityAccessCtrl.createAtManager();atManager.requestPermissionsFromUser(getContext(that), ['ohos.permission.WRITE_IMAGEVIDEO']).then(async () => {let photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.VIDEO;let extension:string = 'mp4';let options: photoAccessHelper.CreateOptions = {title: "record_"+new Date().getTime()+""}let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(getContext(that));phAccessHelper.createAsset(photoType, extension, options, (err, uri) => {if (uri !== undefined) {let recordFile = fs.openSync(that.recordSaveFilePath);let albumFile = fs.openSync(uri,fs.OpenMode.READ_WRITE);fs.copyFileSync(recordFile.fd,albumFile.fd);fs.closeSync(recordFile);fs.closeSync(albumFile);prompt.showToast({message: "停止录制成功"});} else {prompt.showToast({message: "停止录制失败"});}});})})

截屏

    // 保存相册需要申请权限: ohos.permission.WRITE_IMAGEVIDEOlet saveFilePath = getContext(this).cacheDir + "/screen.jpg";this.mIjkMediaPlayer.screenshot(saveFilePath).then((result) => {if(!result) {prompt.showToast({message: "截屏失败"});return;}let atManager = abilityAccessCtrl.createAtManager();atManager.requestPermissionsFromUser(getContext(that), ['ohos.permission.WRITE_IMAGEVIDEO']).then(async () => {let photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.IMAGE;let extension:string = 'jpg';let options: photoAccessHelper.CreateOptions = {title: "screenshot_"+new Date().getTime()+""}let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(getContext(that));phAccessHelper.createAsset(photoType, extension, options, (err, uri) => {if (uri !== undefined) {let screenshotFile = fs.openSync(saveFilePath);let albumFile = fs.openSync(uri,fs.OpenMode.READ_WRITE);fs.copyFileSync(screenshotFile.fd,albumFile.fd);fs.closeSync(screenshotFile);fs.closeSync(albumFile);prompt.showToast({message: "截屏成功"});} else {prompt.showToast({message: "截屏失败"});}});})});

接口说明

IjkMediaPlayer.getInstance()

接口名参数返回值说明
setContextcontext: object, id?: stringvoid设置XComponent回调的context, 设置XComponent的id属性值(可选), 播放视频时需要调用该接口
setDebugopen: booleanvoid设置日志开关
native_setupvoid初始化配置
setDataSourceurl: stringvoid设置视频源地址
setDataSourceHeaderheaders: Map<string, string>void设置视频源的HTTP请求头
setOptioncategory:string, key: string, value: stringvoid设置播放前预设参数(用于设置char类型参数)
setOptionLongcategory:string, key: string, value: stringvoid设置播放前预设参数(用于设置int类型参数)
prepareAsyncvoid加载视频
startvoid播放视频
stopvoid停止播放
pausevoid暂停播放
resetvoid视频重置
releasevoid释放资源
seekTomsec: stringvoid快进、后退
setScreenOnWhilePlayingon: booleanvoid设置屏幕常亮
setSpeedspeed: stringvoid设置播放倍数
getSpeednumber获取设置的倍数
isPlayingboolean查看是否正在播放状态
setOnVideoSizeChangedListenerlistener: OnVideoSizeChangedListenervoid设置获取视频宽高回调监听
setOnPreparedListenerlistener: OnPreparedListenervoid设置视频准备就绪回调监听
setOnInfoListenerlistener: OnInfoListenervoid设置播放器的各种状态回调监听
setOnErrorListenerlistener: OnErrorListenervoid设置播放异常回调监听
setOnBufferingUpdateListenerlistener: OnBufferingUpdateListenervoid设置buffer缓冲回调监听
setOnSeekCompleteListenerlistener: OnSeekCompleteListenervoid设置快进后退回调监听
setMessageListenervoid设置视频监听器到napi用于接收回调
getVideoWidthnumber获取视频宽度
getVideoHeightnumber获取视频高度
getVideoSarNumnumber获取视频宽高比的分子
getVideoSarDennumber获取视频宽高比的分母
getDurationnumber获取视频总的时长
getCurrentPositionnumber获取视频播放当前位置
getAudioSessionIdnumber获取音频sessionID
setVolumeleftVolume: string,rightVolume:stringvoid设置音量
setLoopCountlooping: booleanvoid设置循环播放
isLoopingboolean查看当前是否循环播放
selectTracktrack: stringvoid选择轨道
deselectTracktrack: stringvoid删除选择轨道
getMediaInfoobject获取媒体信息
setAudioIdid: stringvoid设置创建音频对象,设置id
ontype: ‘audioInterrupt’, callback: Callback< InterruptEvent >void监听音频中断事件,使用callback方式返回结果
offtype: ‘audioInterrupt’void取消订阅音频中断事件
startRecordsaveFilePath: stringboolean开启视频录制
isRecordboolean获取视频录制状态
stopRecordPromise停止视频录制
screenshotsaveFilePath: stringPromise截屏

参数说明

  1. InterruptEvent 播放中断时,应用接收的中断事件。
名称类型必填说明
forceTypeInterruptForceType操作是由系统执行或是由应用程序执行。
hintTypeInterruptHint中断提示。
  1. InterruptForceType 枚举,强制打断类型。
名称说明
INTERRUPT_FORCE0由系统进行操作,强制打断音频播放。
INTERRUPT_SHARE1由应用进行操作,可以选择打断或忽略。
  1. InterruptHint 枚举,中断提示。
名称说明
INTERRUPT_HINT_NONE0无提示。
INTERRUPT_HINT_RESUME1提示音频恢复。
INTERRUPT_HINT_PAUSE2提示音频暂停。
INTERRUPT_HINT_STOP3提示音频停止。
INTERRUPT_HINT_DUCK4提示音频躲避。(躲避:音量减弱,而不会停止)
INTERRUPT_HINT_UNDUCK5提示音量恢复。

约束与限制

在下述版本验证通过:

  • DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API12 Release (5.0.0.66)
  • DevEco Studio NEXT 5.0(5.0.3.427)--SDK:API12

监听音频中断事件需保证设备系统版本在22以上。 设置音量需保证SDK版本在12及以上。

目录结构

|---- ijkplayer  
|     |---- entry  # 示例代码文件夹
|     |---- ijkplayer  # ijkplayer 库文件夹
|			|---- cpp  # native模块
|                  |----- ijkplayer # ijkplayer内部业务
|                  |----- ijksdl    # ijkplayer内部业务
|                  |----- napi      # 封装NAPI接口
|                  |----- proxy     # 代理提供给NAPI调用处理ijkplayer内部业务
|                  |----- third_party #三方库依赖 
|                  |----- utils     #工具
|            |---- ets  # ets接口模块
|                  |----- callback  #视频回调接口
|                  |----- common    #常量
|                  |----- utils     #工具  
|                  |----- IjkMediaPlayer.ets #ijkplayer暴露的napi调用接口
|     |---- README_zh.MD  # 安装使用方法                   
http://www.lryc.cn/news/533985.html

相关文章:

  • GRU 和 LSTM 公式推导与矩阵变换过程图解
  • 现在中国三大运营商各自使用的哪些band频段
  • 使用Jenkins实现鸿蒙HAR应用的自动化构建打包
  • AI时代,职场人如何开启学习之旅
  • MIT6.824 Lecture 2-RPC and Threads Lecture 3-GFS
  • MySQL第五次作业
  • 【PDF提取内容】如何批量提取PDF里面的文字内容,把内容到处表格或者批量给PDF文件改名,基于C++的实现方案和步骤
  • 智慧机房解决方案(文末联系,领取整套资料,可做论文)
  • 【C编程问题集中营】使用数组指针时容易踩得坑
  • 【Redis】Linux、Windows、Docker 环境下部署 Redis
  • 反函数定义及其推导
  • 2025.2.9机器学习笔记:PINN文献阅读
  • Oracle数据连接 Dblink
  • fetch请求总结,fastadmin中后台接口强制返回json数据
  • 基于STM32的智能鱼缸水质净化系统设计
  • JAVA安全—FastJson反序列化利用链跟踪autoType绕过
  • 格式化字符串漏洞(Format String Vulnerability)
  • C++--iomanip库
  • Redis 集群原理、主从复制和哨兵模式的详细讲解
  • 基于Java的远程视频会议系统(源码+系统+论文)
  • springboot 事务管理
  • 深度学习-神经机器翻译模型
  • .NET周刊【2月第1期 2025-02-02】
  • 【合集】Java进阶——Java深入学习的笔记汇总 amp; 再论面向对象、数据结构和算法、JVM底层、多线程
  • GPU、CUDA 和 cuDNN 学习研究【笔记】
  • 【5】阿里面试题整理
  • 计算机毕业设计hadoop+spark+hive物流预测系统 物流大数据分析平台 物流信息爬虫 物流大数据 机器学习 深度学习
  • Wpf美化按钮,输入框,下拉框,dataGrid
  • 搜索插入位置:二分查找的巧妙应用
  • Cocos2d-x 游戏开发-打包apk被默认自带了很多不必要的权限导致apk被报毒,如何在Cocos 2d-x中强制去掉不必要的权限-优雅草卓伊凡