03.视频播放器Api说明
时间:2022-07-26
本文章向大家介绍03.视频播放器Api说明,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
03.视频播放器Api说明
目录介绍
- 01.最简单的播放
- 02.如何切换视频内核
- 03.切换视频模式
- 04.切换视频清晰度
- 05.视频播放监听
- 06.列表中播放处理
- 07.悬浮窗口播放
- 08.其他重要功能Api
- 09.播放多个视频
- 10.VideoPlayer相关Api
- 11.Controller相关Api
- 12.边播放边缓存api
- 13.类似抖音视频预加载
- 14.视频播放器埋点
00.视频播放器通用框架
- 基础封装视频播放器player,可以在ExoPlayer、MediaPlayer,声网RTC视频播放器内核,原生MediaPlayer可以自由切换
- 对于视图状态切换和后期维护拓展,避免功能和业务出现耦合。比如需要支持播放器UI高度定制,而不是该lib库中UI代码
- 针对视频播放,音频播放,播放回放,以及视频直播的功能。使用简单,代码拓展性强,封装性好,主要是和业务彻底解耦,暴露接口监听给开发者处理业务具体逻辑
- 该播放器整体架构:播放器内核(自由切换) + 视频播放器 + 边播边缓存 + 高度定制播放器UI视图层
- 项目地址:https://github.com/yangchong211/YCVideoPlayer
- 关于视频播放器整体功能介绍文档:https://juejin.im/post/6883457444752654343
01.最简单的播放
- 必须需要的四步骤代码如下所示//创建基础视频播放器,一般播放器的功能 BasisVideoController controller = new BasisVideoController(this); //设置控制器 mVideoPlayer.setVideoController(controller); //设置视频播放链接地址 mVideoPlayer.setUrl(url); //开始播放 mVideoPlayer.start();
- 开始播放//播放视频 videoPlayer.start();
02.如何切换视频内核
- 创建视频播放器PlayerFactory playerFactory = IjkPlayerFactory.create(); IjkVideoPlayer ijkVideoPlayer = (IjkVideoPlayer) playerFactory.createPlayer(this); PlayerFactory playerFactory = ExoPlayerFactory.create(); ExoMediaPlayer exoMediaPlayer = (ExoMediaPlayer) playerFactory.createPlayer(this); PlayerFactory playerFactory = MediaPlayerFactory.create(); AndroidMediaPlayer androidMediaPlayer = (AndroidMediaPlayer) playerFactory.createPlayer(this);
- 如何配置视频内核//播放器配置,注意:此为全局配置,例如下面就是配置ijk内核播放器 VideoViewManager.setConfig(VideoPlayerConfig.newBuilder() .setLogEnabled(true)//调试的时候请打开日志,方便排错 .setPlayerFactory(IjkPlayerFactory.create()) .build());
- 切换视频内核处理代码@SuppressLint("SetTextI18n") private void setChangeVideoType(@ConstantKeys.PlayerType int type){ //切换播放核心,不推荐这么做,我这么写只是为了方便测试 VideoPlayerConfig config = VideoViewManager.getConfig(); try { Field mPlayerFactoryField = config.getClass().getDeclaredField("mPlayerFactory"); mPlayerFactoryField.setAccessible(true); PlayerFactory playerFactory = null; switch (type) { case ConstantKeys.VideoPlayerType.TYPE_IJK: playerFactory = IjkPlayerFactory.create(); mTvTitle.setText("视频内核:" + " (IjkPlayer)"); break; case ConstantKeys.VideoPlayerType.TYPE_EXO: playerFactory = ExoPlayerFactory.create(); mTvTitle.setText("视频内核:" + " (ExoPlayer)"); break; case ConstantKeys.VideoPlayerType.TYPE_NATIVE: playerFactory = MediaPlayerFactory.create(); mTvTitle.setText("视频内核:" + " (MediaPlayer)"); break; case ConstantKeys.VideoPlayerType.TYPE_RTC: break; } mPlayerFactoryField.set(config, playerFactory); } catch (Exception e) { e.printStackTrace(); } }
03.切换视频模式
- 关于全屏模式相关api//进入全屏 mVideoPlayer.startFullScreen(); //退出全屏 mVideoPlayer.stopFullScreen();
- 关于小窗口播放相关api//开启小屏 mVideoPlayer.startTinyScreen(); //退出小屏 mVideoPlayer.stopTinyScreen();
04.切换视频清晰度
05.视频播放监听
- 这个分为两部分:第一部分是播放模式监听,第二部分是播放状态监听,暴露给开发者。这里不建议使用0,1,非常不方便简明之意,采用注解限定。mVideoPlayer.setOnStateChangeListener(new OnVideoStateListener() { /** * 播放模式 * 普通模式,小窗口模式,正常模式三种其中一种 * MODE_NORMAL 普通模式 * MODE_FULL_SCREEN 全屏模式 * MODE_TINY_WINDOW 小屏模式 * @param playerState 播放模式 */ @Override public void onPlayerStateChanged(int playerState) { switch (playerState) { case ConstantKeys.PlayMode.MODE_NORMAL: //普通模式 break; case ConstantKeys.PlayMode.MODE_FULL_SCREEN: //全屏模式 break; case ConstantKeys.PlayMode.MODE_TINY_WINDOW: //小屏模式 break; } }
/**
* 播放状态
* -1 播放错误
* 0 播放未开始
* 1 播放准备中
* 2 播放准备就绪
* 3 正在播放
* 4 暂停播放
* 5 正在缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,缓冲区数据足够后恢复播放)
* 6 暂停缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,此时暂停播放器,继续缓冲,缓冲区数据足够后恢复暂停
* 7 播放完成
* 8 开始播放中止
* @param playState 播放状态,主要是指播放器的各种状态
*/
@Override
public void onPlayStateChanged(int playState) {
switch (playState) {
case ConstantKeys.CurrentState.STATE_IDLE:
//播放未开始,初始化
break;
case ConstantKeys.CurrentState.STATE_START_ABORT:
//开始播放中止
break;
case ConstantKeys.CurrentState.STATE_PREPARING:
//播放准备中
break;
case ConstantKeys.CurrentState.STATE_PREPARED:
//播放准备就绪
break;
case ConstantKeys.CurrentState.STATE_ERROR:
//播放错误
break;
case ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING:
//正在缓冲
break;
case ConstantKeys.CurrentState.STATE_PLAYING:
//正在播放
break;
case ConstantKeys.CurrentState.STATE_PAUSED:
//暂停播放
break;
case ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED:
//暂停缓冲
break;
case ConstantKeys.CurrentState.STATE_COMPLETED:
//播放完成
break;
}
}
});
```
06.在列表中播放
- 第一步:初始化视频播放器,创建VideoPlayer对象mVideoView = new VideoPlayer(context); mVideoView.setOnStateChangeListener(new VideoPlayer.SimpleOnStateChangeListener() { @Override public void onPlayStateChanged(int playState) { //监听VideoViewManager释放,重置状态 if (playState == ConstantKeys.CurrentState.STATE_IDLE) { PlayerUtils.removeViewFormParent(mVideoView); mLastPos = mCurPos; mCurPos = -1; } } }); mController = new BasisVideoController(context); mVideoView.setController(mController);
- 第二步:设置RecyclerView和AdaptermAdapter.setOnItemChildClickListener(new OnItemChildClickListener() { @Override public void onItemChildClick(int position) { //点击item播放视频 startPlay(position); } }); mRecyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() { @Override public void onChildViewAttachedToWindow(@NonNull View view) {
}
@Override
public void onChildViewDetachedFromWindow(@NonNull View view) {
FrameLayout playerContainer = view.findViewById(R.id.player_container);
View v = playerContainer.getChildAt(0);
if (v != null && v == mVideoView && !mVideoView.isFullScreen()) {
//销毁视频
releaseVideoView();
}
}
});
```
- 第三步:播放视频和销毁视频的逻辑代码/** * 开始播放 * @param position 列表位置 */ protected void startPlay(int position) { if (mCurPos == position) return; if (mCurPos != -1) { releaseVideoView(); } VideoInfoBean videoBean = mVideos.get(position); mVideoView.setUrl(videoBean.getVideoUrl()); View itemView = mLinearLayoutManager.findViewByPosition(position); if (itemView == null) return; VideoRecyclerViewAdapter.VideoHolder viewHolder = (VideoRecyclerViewAdapter.VideoHolder) itemView.getTag(); //把列表中预置的PrepareView添加到控制器中,注意isPrivate此处只能为true。 mController.addControlComponent(viewHolder.mPrepareView, true); PlayerUtils.removeViewFormParent(mVideoView); viewHolder.mPlayerContainer.addView(mVideoView, 0); //播放之前将VideoView添加到VideoViewManager以便在别的页面也能操作它 VideoViewManager.instance().add(mVideoView, "list"); mVideoView.start(); mCurPos = position; }
private void releaseVideoView() {
mVideoView.release();
if (mVideoView.isFullScreen()) {
mVideoView.stopFullScreen();
}
if(getActivity().getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
mCurPos = -1;
}
```
08.其他重要功能Api
- 设置视频播放器背景图,和视频标题。//注意,下面这个controller是指BasisVideoController //设置视频背景图 ImageView thumb = controller.getThumb(); Glide.with(this).load(R.drawable.image_default).into(controller.getThumb()); //设置视频标题 controller.setTitle("视频标题");
- 判断是否锁屏//判断是否锁屏 boolean locked = controller.isLocked(); //设置是否锁屏 controller.setLocked(true);
- 设置播放视频缩放类型。借鉴于网络博客,类似图片缩放。建议选择16:9类型,最常见mVideoPlayer.setScreenScaleType(ConstantKeys.PlayerScreenScaleType.SCREEN_SCALE_16_9); mVideoPlayer.setScreenScaleType(ConstantKeys.PlayerScreenScaleType.SCREEN_SCALE_DEFAULT); mVideoPlayer.setScreenScaleType(ConstantKeys.PlayerScreenScaleType.SCREEN_SCALE_4_3); mVideoPlayer.setScreenScaleType(ConstantKeys.PlayerScreenScaleType.SCREEN_SCALE_MATCH_PARENT); mVideoPlayer.setScreenScaleType(ConstantKeys.PlayerScreenScaleType.SCREEN_SCALE_ORIGINAL); mVideoPlayer.setScreenScaleType(ConstantKeys.PlayerScreenScaleType.SCREEN_SCALE_CENTER_CROP);
09.播放多个视频
- 这个举一个例子,比如同时播放两个视频,当然这种情况在app中可能比较少//必须设置 player1.setUrl(VOD_URL_1); VideoPlayerBuilder.Builder builder = VideoPlayerBuilder.newBuilder(); builder.setEnableAudioFocus(false); VideoPlayerBuilder videoPlayerBuilder = new VideoPlayerBuilder(builder); player1.setVideoBuilder(videoPlayerBuilder); BasisVideoController controller1 = new BasisVideoController(this); player1.setController(controller1); mVideoViews.add(player1);
//必须设置
player2.setUrl(VOD_URL_2);
VideoPlayerBuilder.Builder builder2 = VideoPlayerBuilder.newBuilder();
builder.setEnableAudioFocus(false);
VideoPlayerBuilder videoPlayerBuilder2 = new VideoPlayerBuilder(builder2);
player2.setVideoBuilder(videoPlayerBuilder2);
BasisVideoController controller2 = new BasisVideoController(this);
player2.setController(controller2);
mVideoViews.add(player2);
```
- 那么要是页面切换到后台,如何处理多个视频的暂停功能呢?如下所示:@Override protected void onPause() { super.onPause(); for (VideoPlayer vv : mVideoViews) { vv.pause(); } }
@Override
protected void onResume() {
super.onResume();
for (VideoPlayer vv : mVideoViews) {
vv.pause();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
for (VideoPlayer vv : mVideoViews) {
vv.release();
}
}
@Override
public void onBackPressed() {
for (VideoPlayer vv : mVideoViews) {
if (vv.onBackPressed())
return;
}
super.onBackPressed();
}
```
10.VideoPlayer相关Api
- 关于视频播放相关的api如下所示//暂停播放 mVideoPlayer.pause(); //视频缓冲完毕,准备开始播放时回调 mVideoPlayer.onPrepared(); //重新播放 mVideoPlayer.replay(true); //继续播放 mVideoPlayer.resume(); //调整播放进度 mVideoPlayer.seekTo(100); //循环播放, 默认不循环播放 mVideoPlayer.setLooping(true); //设置播放速度 mVideoPlayer.setSpeed(1.1f); //设置音量 0.0f-1.0f 之间 mVideoPlayer.setVolume(1,1); //开始播放 mVideoPlayer.start();
- 关于视频切换播放模式相关api//判断是否处于全屏状态 boolean fullScreen = mVideoPlayer.isFullScreen(); //是否是小窗口模式 boolean tinyScreen = mVideoPlayer.isTinyScreen(); //进入全屏 mVideoPlayer.startFullScreen(); //退出全屏 mVideoPlayer.stopFullScreen(); //开启小屏 mVideoPlayer.startTinyScreen(); //退出小屏 mVideoPlayer.stopTinyScreen();
- 关于其他比如获取速度,音量,设置属性相关Api//VideoPlayer相关 VideoPlayerBuilder.Builder builder = VideoPlayerBuilder.newBuilder(); VideoPlayerBuilder videoPlayerBuilder = new VideoPlayerBuilder(builder); //设置视频播放器的背景色 builder.setPlayerBackgroundColor(Color.BLACK); //设置小屏的宽高 int[] mTinyScreenSize = {0, 0}; builder.setTinyScreenSize(mTinyScreenSize); //是否开启AudioFocus监听, 默认开启 builder.setEnableAudioFocus(false); mVideoPlayer.setVideoBuilder(videoPlayerBuilder); //截图 Bitmap bitmap = mVideoPlayer.doScreenShot(); //移除所有播放状态监听 mVideoPlayer.clearOnStateChangeListeners(); //获取当前缓冲百分比 int bufferedPercentage = mVideoPlayer.getBufferedPercentage(); //获取当前播放器的状态 int currentPlayerState = mVideoPlayer.getCurrentPlayerState(); //获取当前的播放状态 int currentPlayState = mVideoPlayer.getCurrentPlayState(); //获取当前播放的位置 long currentPosition = mVideoPlayer.getCurrentPosition(); //获取视频总时长 long duration = mVideoPlayer.getDuration(); //获取倍速速度 float speed = mVideoPlayer.getSpeed(); //获取缓冲速度 long tcpSpeed = mVideoPlayer.getTcpSpeed(); //获取视频宽高 int[] videoSize = mVideoPlayer.getVideoSize(); //是否处于静音状态 boolean mute = mVideoPlayer.isMute();
11.Controller相关Api
- Controller控制器相关的Api说明//设置视频背景图 ImageView thumb = controller.getThumb(); Glide.with(this).load(R.drawable.image_default).into(controller.getThumb()); //设置视频标题 controller.setTitle("视频标题"); //添加自定义视图。每添加一个视图,都是方式层级树的最上层 CustomErrorView customErrorView = new CustomErrorView(this); controller.addControlComponent(customErrorView); //移除控制组件 controller.removeControlComponent(customErrorView); //移除所有的组件 controller.removeAllControlComponent(); //隐藏播放视图 controller.hide(); //显示播放视图 controller.show(); //是否开启根据屏幕方向进入/退出全屏 controller.setEnableOrientation(true); //显示移动网络播放提示 controller.showNetWarning(); //刘海的高度 int cutoutHeight = controller.getCutoutHeight(); //是否有刘海屏 boolean b = controller.hasCutout(); //设置是否适配刘海屏 controller.setAdaptCutout(true); //停止刷新进度 controller.stopProgress(); //开始刷新进度,注意:需在STATE_PLAYING时调用才会开始刷新进度 controller.startProgress(); //判断是否锁屏 boolean locked = controller.isLocked(); //设置是否锁屏 controller.setLocked(true); //取消计时 controller.stopFadeOut(); //开始计时 controller.startFadeOut(); //设置播放视图自动隐藏超时 controller.setDismissTimeout(8); //销毁 controller.destroy();
12.边播放边缓存api
- 如下所示controller = new BasisVideoController(this); //设置视频背景图 Glide.with(this).load(R.drawable.image_default).into(controller.getThumb()); //设置控制器 mVideoPlayer.setController(controller); HttpProxyCacheServer server = new HttpProxyCacheServer(this); String proxyVideoUrl = server.getProxyUrl(URL_AD); mVideoPlayer.setUrl(proxyUrl); mVideoPlayer.start();
13.类似抖音视频预加载
- 如下所示,这个是针对ViewPager//获取PreloadManager预加载管理者对象 mPreloadManager = PreloadManager.getInstance(this); //在播放视频的时候 String playUrl = mPreloadManager.getPlayUrl(url); VideoLogUtils.i("startPlay: " + "position: " + position + " url: " + playUrl); mVideoPlayer.setUrl(playUrl); //在页面滚动的时候 mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageScrollStateChanged(int state) { super.onPageScrollStateChanged(state); if (state == VerticalViewPager.SCROLL_STATE_IDLE) { mPreloadManager.resumePreload(mCurPos, mIsReverseScroll); } else { mPreloadManager.pausePreload(mCurPos, mIsReverseScroll); } } });
- 如下所示,这个是针对RecyclerViewrecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { /** * 是否反向滑动 */ private boolean mIsReverseScroll;
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy>0){
//表示下滑
mIsReverseScroll = false;
} else {
//表示上滑
mIsReverseScroll = true;
}
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == VerticalViewPager.SCROLL_STATE_IDLE) {
mPreloadManager.resumePreload(mCurPos, mIsReverseScroll);
} else {
mPreloadManager.pausePreload(mCurPos, mIsReverseScroll);
}
}
});
```
14.视频播放器埋点
- 代码如下所示,写一个类,实现BuriedPointEvent即可。即可埋点视频的播放次数,播放进度,点击视频广告啥的,方便统一管理public class BuriedPointEventImpl implements BuriedPointEvent { /** * 进入视频播放 * @param url 视频url */ @Override public void playerIn(String url) { } /** * 退出视频播放 * @param url 视频url */ @Override public void playerDestroy(String url) { } /** * 视频播放完成 * @param url 视频url */ @Override public void playerCompletion(String url) { } /** * 视频播放异常 * @param url 视频url * @param isNetError 是否是网络异常 */ @Override public void onError(String url, boolean isNetError) { } /** * 点击了视频广告 * @param url 视频url */ @Override public void clickAd(String url) { } /** * 退出视频播放时候的播放进度百度分 * @param url 视频url * @param progress 视频进度,计算百分比【退出时候进度 / 总进度】 */ @Override public void playerOutProgress(String url, float progress) { } /** * 视频切换音频 * @param url 视频url */ @Override public void videoToMedia(String url) { } }
15.播放器示例展示图
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 最近面试碰到的两道算法题|面试相关
- Thread也会OOM吗?
- RoundCube Webmail邮件正文存储型XSS(CVE-2015-1433)
- 再谈Android Lint
- Android DiffUtil 封装|深拷贝
- [CVE-2014-8959] phpmyadmin任意文件包含漏洞分析
- Android 统计页面渲染时长
- Transform和Task之间有关?| Gradle
- user.ini文件构成的PHP后门
- Android厂商推送Plugin化 | 掘金技术征文-双节特别篇
- 关于lnmp目录禁止执行的绕过与正确方法
- Quill编辑器自定义字体和字体大小
- emlog某重要插件前台SQL注入+Getshell
- ES6中的对象与类
- QQ某业务主站DOM XSS挖掘与分析(绕过WAF)