Android 修復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(停止後最後執行一次)

實現代碼如下:

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);
      }
    }
  };

  // ....................代碼省略.............................
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章