修复ijkPlayer进行m3u8 hls流播放时seek进度条拖动不准确的问题

项目中使用的播放器是ijkPlayer,发现播放切片特点的hls流(m3u8格式的视频)拖动seekBar的时候会莫名的跳转或者seek不到准确的位置,发现网友也遇到了同样的问题,ijk的开发者也说明了是因为UI层的问题导致的,需要自己排查。涉及到该问题的链接:

既然开发者都说了,那么就老实分析代码吧。因为项目中用到的MediaController继承自Android系统的MediaController,所以还得看看源码,分析得出系统中实现是将seek的listener监听器放在onProgressChanged这个方法中,这也是为什么我们断断续续拖动的时候播放器也会播放,知道这点就够了,把onProgressChanged中的mPlayer.seekTo((int) newposition);放到onStopTrackingTouch方法中。

执行顺序是:

onStartTrackingTouch(执行一次) —> onProgressChanged(拖动就会不停的执行) —> onStopTrackingTouch(停止后最后执行一次)

实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class CustomMediaController extends MediaController implements ICustomMediaController {
// ....................代码省略.............................

// There are two scenarios that can trigger the seekbar listener to trigger:
//
// The first is the user using the touchpad to adjust the posititon of the
// seekbar's thumb. In this case onStartTrackingTouch is called followed by
// a number of onProgressChanged notifications, concluded by onStopTrackingTouch.
// We're setting the field "mDragging" to true for the duration of the dragging
// session to avoid jumps in the position in case of ongoing playback.
//
// The second scenario involves the user operating the scroll ball, in this
// case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications,
// we will simply apply the updated position without suspending regular updates.
private OnSeekBarChangeListener mSeekListener=new OnSeekBarChangeListener(){
long newposition;

public void onStartTrackingTouch(SeekBar bar){
show(3600000);
mDragging=true;
if(seekerBarDraggingListener!=null)
seekerBarDraggingListener.getCurrentDraggingstatus(mDragging);

// By removing these pending progress messages we make sure
// that a) we won't update the progress while the user adjusts
// the seekbar and b) once the user is done dragging the thumb
// we will post one of these messages to the queue again and
// this ensures that there will be exactly one message queued up.
mHandler.removeMessages(SHOW_PROGRESS);
}

public void onProgressChanged(SeekBar bar,int progress,boolean fromuser){
if(!fromuser){
// We're not interested in programmatically generated changes to
// the progress bar's position.
return;
}
long duration=mPlayer.getDuration();
newposition=(duration*progress)/1000L;
// 系统原来的实现是在progress改变的时候时刻都在进行videoplayer的seek
//这会导致seek m3u8切片文件的时候拖动seek时不准确,所以需要在拖动完成后才进行播放器的seekTo()
// mPlayer.seekTo((int) newposition);
if(mCurrentTime!=null)
mCurrentTime.setText(stringForTime((int)newposition));
}

public void onStopTrackingTouch(SeekBar bar){
mDragging=false;
mPlayer.seekTo((int)newposition);
if(seekerBarDraggingListener!=null)
seekerBarDraggingListener.getCurrentDraggingstatus(mDragging);
setProgress();
updatePausePlay();
if(isntNeedStayShowAfterDrag){
show(sDefaultTimeout);
// Ensure that progress is properly updated in the future,
// the call to show() does not guarantee this because it is a
// no-op if we are already showing.
mHandler.sendEmptyMessage(SHOW_PROGRESS);
}
}
};

// ....................代码省略.............................
}