想着练习下学习下 ijkplayer ,但不知道做个啥,就想着做个今日头条类似的视频播放列表,当item滑出了可视区域就自动播放下一个视频,因为播放器需要opengl渲染,所以就需要glsurfaceview,最开始的思路就是每个item都有一个surfaceview然后新建一个IjkMediaPlayer.使用后发现还没加入播放等动作就已经卡顿的不得了。如下图:
条状图就是手机开启了gpu呈现模式分析(在绿色横线以下就是每帧<=16ms)大于就是有些卡顿了,对于滚动界面来说就有必要优化了。
后来改换思路整个列表只使用一个MyVideoView(glsurfaceview+ijkplayer的整合)
然后通过addview到指定的item中,然后跟随滑动,就普通的addview,removeview这两个操作就已经要60ms左右,这对于一个滑动列表肯定也是不行的,不过相对之前已经有所进步了。
最后想干脆我也不addview进去了,直接新建一个MyVideoView,滑动的时候跟随着滑动,不addview也不用removeview,就简单的跟随滑动,发现要完全滑出了界面,就自动播放下一个item视频。
滑动效果如下:感觉已经能满足需求了(视频的播放暂停,进度条没加入进去,这个不会影响滑动卡顿问题,添加简单所以就没继续写了。)
gif效果图:
现在简单看看代码:
MyVideoView(是GlSurfaceView 和ijkPlayer的封装):
public void play(final String path) {
new Thread() {
@Override
public void run() {
super.run();
synchronized (MyVideoView.class) {
try {
playRelease();
player = new IjkMediaPlayer();
player.setDisplay(surfaceView.getHolder());
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDataSource(path);
player.prepareAsync();
player.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(IMediaPlayer iMediaPlayer) {
if (lis != null) lis.startSuccess();
iMediaPlayer.start();
Log.e("xhc", " start ...");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
}
将Ijkplayer的释放,新建,都是在子线程中处理的,为的就是不阻塞主线程。
下面来看看recycleview的滑动事件的监听把:
if(currentPosition >= 0 && currentPosition < adapter.getItemCount()){
/**
* 1.正在播放的视频已经滑出去,a.自动播放下一条,autoPlay = true b.播放器停止autoPlay = false
* 2.正在播放的视频还在可视区域 a.继续播放
*/
if(currentPosition < linearLayoutManager.findFirstVisibleItemPosition() && autoPlay){
//自动播放下一条
lastPosition = currentPosition;
currentPosition = linearLayoutManager.findFirstVisibleItemPosition();
playVideo(currentPosition , listVB.get(currentPosition));
}
else if(currentPosition > linearLayoutManager.findLastVisibleItemPosition() && autoPlay){
lastPosition = currentPosition;
currentPosition = linearLayoutManager.findLastVisibleItemPosition();
playVideo(currentPosition , listVB.get(currentPosition));
}
else if((currentPosition < linearLayoutManager.findFirstVisibleItemPosition() ||
currentPosition > linearLayoutManager.findLastVisibleItemPosition()) && !autoPlay){
//没有自动播放,如果超出了可视区域直接停止播放器
new Thread(){
@Override
public void run() {
super.run();
mv.playRelease();
}
}.start();
return ;
}
contain.setTranslationY(linearLayoutManager.findViewByPosition(currentPosition).getY());
}
}
基本逻辑就是
1.当前播放的视频的position是比当前可视界面的第一个item的position还小,那么就播放下一个
2.如果当前视频的item的position比可视界面的最后一个还大,就播放上条视频。
VideoBean vb = new VideoBean();
vb.setVideoPath("sdcard/FFmpeg/video_src/v1080.mp4");
VideoBean vb2 = new VideoBean();
vb2.setVideoPath("sdcard/FFmpeg/video_src/test.mp4");
VideoBean vb3 = new VideoBean();
vb3.setVideoPath("sdcard/FFmpeg/video_src/time.mp4");
VideoBean vb4 = new VideoBean();
vb4.setVideoPath("sdcard/FFmpeg/video_src/input.mp4");
VideoBean vb5 = new VideoBean();
vb5.setVideoPath("rtmp://58.200.131.2:1935/livetv/hunantv");
VideoBean vb6 = new VideoBean();
vb6.setVideoPath("rtmp://media3.sinovision.net:1935/live/livestream");
测试视频有本地一些mp4和一些rmtp网络流,因为rtmp的网络给予tcp并且自己也要握手,所以加载时间更久点。
视频的测试文件在项目中可看到