需求
产品经理说:要实现两个播放器同时播放不同的视频,暂停啊快进啊播放完成啊这些状态都要同步,播放过程中如果出现某一个视频在缓冲中,那么另外一个视频就得等待缓冲视频缓冲完成,然后才继续播放。
因为之前接触播放器的经验不多,所以感觉无从下手,生无可恋,不知道怎么同步,也不知道如何让一个视频等待另外一个视频。
先上代码链接,效果视频在res的raw文件夹下,大家可以看下效果视频然后再看是否符合自己的实际需求
github
问题
- 如果某一个播放器还在初始化,但是另外一个已经准备好开始播放了,这时候我们需要暂停播放中的,等前边一个播放器初始化好了,再一起继续播放。
- 如何做到某一个播放器在缓冲中,让另外一个播放器等待呢?等缓冲完成之后再两个播放器同时播。
- 快进或者快退之后,需要等待两个播放器都缓冲好了才继续播。
分析
- 第一:其实上边所有的基础,都是基于一个前提,就是以第一个播放器的状态和进度为基准,后边的播放器都向它对齐。
- 第二:我们必须在计时器中进行上述问题的处理,因为计时器每隔1s就更新一次,有问题或者不同步能及时纠正。
- 第三:如果有一个播放器是准备中或者缓冲中,就暂停其他播放器,这个暂停为自动暂停,缓冲完成之后是可以继续播放的。
知道思路,剩下的就是编码体力活了。代码如下
判断两个播放器进度是否一致(这里有个容错参数,只要播放器进度差值小于2000都算进度一致)
private boolean judgePlayerProgressSame(int currentFlag, int otherFlag) {
int currentProgress = mProgressArray.get(currentFlag);
int otherProgress = mProgressArray.get(otherFlag);
int abs = Math.abs(currentProgress - otherProgress);
return abs < 2000;
}
当两个播放器状态一致时,判断进度差值是否一样,如果不同则暂停所有播放器,然后将第二个播放器的进度seekTo到第一个播放器的进度。
如果当前状态是自动暂停,则两个播放器继续播放
private void playerStateSame(int flag, int otherFlag) {
int currentPlayState = mStateArray.get(flag);
Log.e(TAG, "setVideoProgress 两个播放器状态一致," + mStateArray.get(0) + "--" + mStateArray.get(1));
if (currentPlayState == PlayerConstant.CURRENT_STATE_PLAYING) { // 正在播放
boolean same = judgePlayerProgressSame(flag, otherFlag);
if (!same) {
Log.e(TAG, "setVideoProgress 两个播放器状态都是播放中,但是前后时间不一致");
pauseAllPlayerByMyself();
seekToSameProgress();
}
} else if (currentPlayState == PlayerConstant.CURRENT_STATE_PAUSE_MYSELF) { // 开始播放
boolean same = judgePlayerProgressSame(flag, otherFlag);
Log.e(TAG, "setVideoProgress 两个播放器状态都是自我暂停中,但是前后时间不一致");
if (same) {
playAllPlayerByMyself();
}
// else {
// seekToSameProgress();
// }
}
}
暂停所有播放器,将其他播放器进度seekTo到第一个播放器的进度。
private void pauseAllPlayerByMyself() {
for (PlayerController controller : mPlayerControllerList) {
controller.pauseByMyself();
}
}
private void seekToSameProgress() {
PlayerController otherController = getPlayerControllerByFlag(1);
int progress = mProgressArray.get(0);
otherController.seekTo(progress);
}
如果两个播放器状态不一致,则暂停播放器
private void playerStateDifferent(int flag, int otherFlag) {
int currentState = mStateArray.get(flag);
int otherState = mStateArray.get(otherFlag);
if (currentState == PlayerConstant.CURRENT_STATE_PLAYING && otherState == PlayerConstant.CURRENT_STATE_PREPARING) {
Log.e(TAG, "一个播放中,一个是准备中");
PlayerController playerController = getPlayerControllerByFlag(flag);
playerController.pauseByMyself();
} else if (currentState == PlayerConstant.CURRENT_STATE_PLAYING && otherState == PlayerConstant.CURRENT_STATE_PAUSE_MYSELF) {
Log.e(TAG, "一个播放中,一个是自我暂停");
PlayerController playerController = getPlayerControllerByFlag(flag);
playerController.pauseByMyself();
}
}
当播放器缓冲完成的时候,需要判断是不是自我暂停状态(也就是播放器自己暂停状态)
@Override public void onSeekComplete(int flag) { // 快进完成
if (mPlayerControllerList.size() > 1) {
if (mStopTrackingTouchStatus == PlayerConstant.CURRENT_STATE_PAUSE) {
getPlayerControllerByFlag(flag).goOnPlayOnPause();
return;
}
if (mStateArray.get(flag) == PlayerConstant.CURRENT_STATE_SEEKING) {
pausePlayerByMyself(flag);
}
int otherFlag = getOtherFlag(flag);
if (judgePlayerStateSame(flag, otherFlag)) {
int currentPlayState = mStateArray.get(flag);
if (currentPlayState == PlayerConstant.CURRENT_STATE_PAUSE_MYSELF || judgePlayerProgressSame(flag, otherFlag)) { // 开始播放
Log.e(TAG, "快进完成,执行播放" + flag);
playAllPlayerByMyself();
}
}
}
}
播放器的常量值
public static final int CURRENT_STATE_NORMAL= 0; // 正常
public static final int CURRENT_STATE_PREPARING= 1; // 准备中
public static final int CURRENT_STATE_PREPARING_CHANGING_URL = 2;
public static final int CURRENT_STATE_PLAYING= 3; // 播放中
public static final int CURRENT_STATE_PAUSE= 5; // 暂停-用户暂停
public static final int CURRENT_STATE_PAUSE_MYSELF= 50; // 暂停-因为两个视频进度不一致自动暂停
public static final int CURRENT_STATE_AUTO_COMPLETE= 6; // 播放完成
public static final int CURRENT_STATE_ERROR= 7; // 错误
public static final int CURRENT_STATE_SEEKING= 8; // 快进快退加载中