項目中使用的播放器是ijkPlayer,發現播放切片特點的hls流(m3u8格式的視頻)拖動seekBar的時候會莫名的跳轉或者seek不到准確的位置,發現網友也遇到了同樣的問題,ijk的開發者也說明了是因為UI層的問題導致的,需要自己排查。涉及到該問題的鏈接:
-
通過ijkPlayer播放m3u8視頻時快進不准確的解決方案
-
為什么Sample里面的進度條,往前拖動進度條后,還會往后退幾秒
-
向前拖動,進度條會往回跳
https://github.com/Bilibili/ijkplayer/issues/313
**bbcallen **commented on Jul 8, 2015
UI部分seekbar的回調處理得不太合理,如果放手很快,最后一個位置不會被傳給播放器,建議自行修改。
既然開發者都說了,那么就老實分析代碼吧。因為項目中用到的MediaController
繼承自Android系統的MediaController
,所以還得看看源碼,分析得出系統中實現是將seek的listener監聽器放在onProgressChanged
這個方法中,這也是為什么我們斷斷續續拖動的時候播放器也會播放,知道這點就夠了,把onProgressChanged
中的mPlayer.seekTo((int) newposition);
放到onStopTrackingTouch
方法中。
執行順序是:
onStartTrackingTouch(執行一次) —> onProgressChanged(拖動就會不停的執行) —> onStopTrackingTouch(停止后最后執行一次)
實現代碼如下:
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);
}
}
};
// ....................代碼省略.............................
}