Android MediaPlayer SeekTo 在 8.0 版本上優化說明
阿新 • • 發佈:2018-09-04
data overhead from lar ide mes ace chan policy
android使用 mediaPlayer 播放video視頻過程中, 當用戶退出當前播放,再從後臺恢復播放時,需要跳轉到之前退出的時間點繼續播放。使用的方法基本都是 SeekTo 之前的時間點,但是經常遇到恢復播放時位置不準的問題,而且甚至有重頭開始播放的現象。這個是因為SeekTo是回到上一時間點附近的關鍵幀導致的。
針對這個問題,在最新的android 8.0平臺上,已經有了新的解決方案:
SeekTo() 方法在android O 平臺新增了一個多參數的方法:
void seekTo(long msec, @SeekMode int mode)
這裏的Mode 傳入
int SEEK_CLOSEST = 0x03
就不會出現播放視頻位置不準確的現象了。
/** * Seek modes used in method seekTo(long, int) to move media position * to a specified location. * * Do not change these mode values without updating their counterparts * in include/media/IMediaSource.h! */ /** * This mode is used with {@link#seekTo(long, int)} to move media position to * a sync (or key) frame associated with a data source that is located * right before or at the given time. * * @see #seekTo(long, int) */ public static final int SEEK_PREVIOUS_SYNC = 0x00; /** * This mode is used with {@link #seekTo(long, int)} to move media position to * a sync (or key) frame associated with a data source that is located * right after or at the given time. * * @see #seekTo(long, int) */ public static final int SEEK_NEXT_SYNC = 0x01; /** * This mode is used with {@link #seekTo(long, int)} to move media position to * a sync (or key) frame associated with a data source that is located * closest to (in time) or at the given time. * * @see #seekTo(long, int) */ public static final int SEEK_CLOSEST_SYNC = 0x02; /** * This mode is used with {@link #seekTo(long, int)} to move media position to * a frame (not necessarily a key frame) associated with a data source that * is located closest to or at the given time. * * @see #seekTo(long, int) */ public static final int SEEK_CLOSEST = 0x03; /** @hide */ @IntDef( value = { SEEK_PREVIOUS_SYNC, SEEK_NEXT_SYNC, SEEK_CLOSEST_SYNC, SEEK_CLOSEST, }) @Retention(RetentionPolicy.SOURCE) public @interface SeekMode {} private native final void _seekTo(long msec, int mode); /** * Moves the media to specified time position by considering the given mode. * <p> * When seekTo is finished, the user will be notified via OnSeekComplete supplied by the user. * There is at most one active seekTo processed at any time. If there is a to-be-completed * seekTo, new seekTo requests will be queued in such a way that only the last request * is kept. When current seekTo is completed, the queued request will be processed if * that request is different from just-finished seekTo operation, i.e., the requested * position or mode is different. * * @param msec the offset in milliseconds from the start to seek to. * When seeking to the given time position, there is no guarantee that the data source * has a frame located at the position. When this happens, a frame nearby will be rendered. * If msec is negative, time position zero will be used. * If msec is larger than duration, duration will be used. * @param mode the mode indicating where exactly to seek to. * Use {@link #SEEK_PREVIOUS_SYNC} if one wants to seek to a sync frame * that has a timestamp earlier than or the same as msec. Use * {@link #SEEK_NEXT_SYNC} if one wants to seek to a sync frame * that has a timestamp later than or the same as msec. Use * {@link #SEEK_CLOSEST_SYNC} if one wants to seek to a sync frame * that has a timestamp closest to or the same as msec. Use * {@link #SEEK_CLOSEST} if one wants to seek to a frame that may * or may not be a sync frame but is closest to or the same as msec. * {@link #SEEK_CLOSEST} often has larger performance overhead compared * to the other options if there is no sync frame located at msec. * @throws IllegalStateException if the internal player engine has not been * initialized * @throws IllegalArgumentException if the mode is invalid. */ public void seekTo(long msec, @SeekMode int mode) { if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) { final String msg = "Illegal seek mode: " + mode; throw new IllegalArgumentException(msg); } // TODO: pass long to native, instead of truncating here. if (msec > Integer.MAX_VALUE) { Log.w(TAG, "seekTo offset " + msec + " is too large, cap to " + Integer.MAX_VALUE); msec = Integer.MAX_VALUE; } else if (msec < Integer.MIN_VALUE) { Log.w(TAG, "seekTo offset " + msec + " is too small, cap to " + Integer.MIN_VALUE); msec = Integer.MIN_VALUE; } _seekTo(msec, mode); }
Android MediaPlayer SeekTo 在 8.0 版本上優化說明