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

  // ....................代码省略.............................
}
posted @ 2016-11-09 16:24  Codios  阅读(6139)  评论(0编辑  收藏  举报