本文章為原創(chuàng),轉載時請注明出處
實現 Android 的視頻播放,通常有以下幾種方式
1.使用自帶的播放器,指定 Action 為 ACTION_VIEW,Data 為 Uri,Type 為其 MIME 類型。
2.使用 VideoView 來播放,在布局文件中使用 VideoView 結合
MediaController 來實現對其控制。
3.使用 MediaPlayer 類和 SurfaceView 來實現,這種方式很靈活。
使用 VideoView 播放視頻的步驟:
1.在界面布局文件中定義 VideoView 組件,或在程序中創(chuàng)建
VideoView 組件
2.調用 VideoView 的如下兩個方法來加載指定的視頻
setVidePath(String path) // 加載path文件代表的視
setVideoURI(Uri uri) // 加載uri所對應的視頻
3.調用 start()、stop()、pause()方法來控制視頻的播放
4.通過與 MediaController 類結合使用,開發(fā)者可以不用自己控制播放與暫停
調用 seekTo 方法跳轉不準的問題
典型場景:
當用戶從后臺恢復播放界面時,需要跳轉到之前退出的時間點繼續(xù)播放原來的視頻。其實現邏輯大致上是:
- 在暫停時保存當前
VideoView的currantPosition進度 - 恢復播放時,調用
seekTo方法,傳入currantPosition作為跳轉參數
按照官方提供的 API 來看,這是最合理的使用方式。但在某些情況下,我們會遇到視頻恢復播放時進度位置不準的問題,甚至有些會重頭開始播放。
下面就針對使用 VideoView 播放視頻時 seekTo 跳轉不準的問題進行分析。
問題定位
1. 消除方法異步執(zhí)行的影響
首先明確一點: *** VideoView 的 seekTo 方法是異步執(zhí)行的***,因此會有 seek 未完成但播放已經開始的現象。需要消除 seekTo 對恢復播放的影響,應該在 seek 操作完成的 seekComplete 回調方法中執(zhí)行 ViedeoView 的 start 方法。
Tip:
seekComplete屬于MediaPlayer類的OnPreparedListener監(jiān)聽器的一個回調方法。雖然VideoView是基于MediaPlayer實現的,但沒提供setOnSeekCompleteListener設置監(jiān)聽器的方法,所以我們要拿到VideoView內部持有MediaPlayer對象。
// 設置 VideoView 的 OnPrepared 監(jiān)聽,拿到 MediaPlayer 對象。
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//設置 MediaPlayer 的 OnSeekComplete 監(jiān)聽
mp.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
// seekTo 方法完成時的回調
if(isPause){
videoView.start();
isPause = false;
}
}
});
}
});
2. 消除視頻源的問題
其實 seekTo 跳轉的位置其實并不是參數所帶的 position,而是離 position 最近的視頻關鍵幀。
關于視頻關鍵幀建議大家可以去了解一下相關知識,大致上就是視頻播放時需要從一個關鍵幀的位置開始。
所以當視頻在跳轉到相應的 position 位置缺少關鍵幀的情況下,調用 seekTo 方法是無法在當前位置開始播放。這時會尋找離指定 position 最近的關鍵幀位置開始播放。
關于視頻源造成的問題,可以采取以下解決措施:
- 替換成滿足需求的視頻源文件(尋找合格的視頻文件)
- 對視頻源文件進行處理,增加其關鍵幀數量,比如可以1s設置一個關鍵幀(基于目前已有的視頻文件進行處理)。
如果選擇第二種方式,要增加視頻的關鍵幀數量,可以推薦大家使用FFmpeg進行增加關鍵幀的處理工作。 http://ffmpeg.org/
FFmpeg 工具相關命令行語句:
ffmpeg.exe -i "D:\in.mp4" -c:v libx264 -preset superfast -x264opts keyint=25 -acodec copy -f mp4 "D:\out.mp4"
命令語句大致意思是:在 D 盤路徑下把 in.mp4 視頻文件每隔 25 幀設置一個關鍵幀,音軌保持原視頻參數,其余使用 FFmpeg 提供的default 值,最后保存為 out.mp4 文件到 D 盤。
總結
在深究問題的原因時不可淺嘗而止,也不要一味的懷疑是不是代碼造成了問題。很多情況下都選擇盲目地替換不同的視頻組件出實現,而忽略了視頻源文件本身的問題。