最近公司個廣告機的項目要實現(xiàn)幾段視頻的無縫切換播放功能辣垒,我在網(wǎng)上找了一圈,發(fā)現(xiàn)網(wǎng)上說能實現(xiàn)實現(xiàn)視頻無縫切換功能的都是用的surfaceview+mediaplayer印蔬,于是我開始漫漫的爬坑之路。
先簡單介紹下surfaceview和mediaplayer脱衙,surfaceview有兩級緩存機制侥猬,在播放著這幀視頻的時候例驹,會將下幀視頻緩存到內(nèi)存里,能夠很好的保證視頻播放的流暢性退唠。mediaplayer是安卓的一個原生類鹃锈,接下來的很多坑都是關(guān)于mediaplayer的。先看下mediaplayer的生命周期:
首先我們實例化兩個mediaplayer對象:
>MediaPlayer mCurrentMediaPlayer, mNextMediaPlayer;
>mCurrentMediaPlayer = new MediaPlayer();
>mNextMediaPlayer = new MediaPlayer();
此時的mCurrentMediaPlayer和mNextMediaPlayer對象還沒有被賦予資源瞧预,處于生命周期的Idle狀態(tài)接著我們可以用setDataSource()來給MediaPlayer對象設(shè)置資源:
>mCurrentMediaPlayer.setDataSource(SubWayPlayerActivity.this, Uri.parse(path));
MediaPlayer對象被賦予資源之后屎债,就處于Initialized狀態(tài),在此狀態(tài)調(diào)用prepare()+start()方法即可播放視頻垢油。我選用的是prepareAsync()即異步裝載方式盆驹,然后需要在OnPreparedListener監(jiān)聽中調(diào)用start方法來啟動視頻播放。而mediaplayer的reset()方法可以釋放mediaplayer的資源滩愁,將對象初始化到Idle狀態(tài)躯喇。
實現(xiàn)視頻無縫切換功能的基本思路是:先將mCurrentMediaPlayer對象播放在mVideoSurface上,然后用getDuration()方法獲取這段視頻的時長硝枉,在mCurrentMediaPlayer中的視頻快播放完畢時廉丽,用mNextMediaPlayer對象加載下一段視頻,加載完畢時妻味,調(diào)用start方法顯示出來正压,然后把mCurrentMediaPlayer的資源釋放,隱藏mVideoSurface责球。如此循環(huán)焦履。
下面貼出surfaceview的初始化代碼:
?mVideoSurface = new SurfaceView(this);
mVideoSurface.getHolder().addCallback(new VideoSurfaceHodlerCallback());
mNextSurface = new SurfaceView(this);
mNextSurface.getHolder().addCallback(new NextVideoSurfaceHodlerCallback());
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
lp.gravity = Gravity.LEFT | Gravity.TOP;
mVideoSurface.setLayoutParams(lp);
FrameLayout.LayoutParams lps = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
lp.gravity = Gravity.LEFT | Gravity.TOP;
mNextSurface.setLayoutParams(lps);
mFrame.addView(mNextSurface);
mFrame.addView(mVideoSurface);
接下來要實現(xiàn)surfaceview的三個回調(diào)函數(shù):
接下來貼出實現(xiàn)切換的線程代碼:
class VideoSurfaceHodlerCallback implements SurfaceHolder.Callback {
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
@Override
public void surfaceCreated(SurfaceHolder holder){
mCurrentMediaPlayer.setDisplay(mVideoSurface.getHolder());
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) { } }
Runnable mPlayRun = new Runnable() {
@Override
public void run() {
String path = paths[mIndex % paths.length];
try { if (mIndex % 2 == 0) { mIndex++; mCurrentMediaPlayer.reset();
mVideoSurface.setVisibility(View.VISIBLE);
mCurrentMediaPlayer.setDataSource(MainActivity.this, Uri.parse(path));
mCurrentMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer arg0) {
mCurrentMediaPlayer.start();
mNextMediaPlayer.reset();
mNextSurface.setVisibility(View.INVISIBLE);
mHandler.postDelayed(mPlayRun, mCurrentMediaPlayer.getDuration()-230); } });
mCurrentMediaPlayer.prepareAsync();
} else {
mIndex++; mNextMediaPlayer.reset();
mNextSurface.setVisibility(View.VISIBLE);
mNextMediaPlayer.setDataSource(MainActivity.this, Uri.parse(path));
mNextMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override
public void onPrepared(MediaPlayer arg0) {
mNextMediaPlayer.start(); mCurrentMediaPlayer.reset();
mVideoSurface.setVisibility(View.INVISIBLE);
mHandler.postDelayed(mPlayRun, mNextMediaPlayer.getDuration()-230); } });
mNextMediaPlayer.prepareAsync();
} } catch (Exception e) {
e.printStackTrace(); } } };
接下來貼出初始化方法代碼:
private void VideoInit() {
mHandler = new Handler();
mCurrentMediaPlayer = new MediaPlayer();
mNextMediaPlayer = new MediaPlayer();
mVideoSurface.getHolder().addCallback(new VideoSurfaceHodlerCallback()); ?
mNextSurface.getHolder().addCallback(new NextVideoSurfaceHodlerCallback());
mHandler.postDelayed(mPlayRun, 1000); }
以上代碼就是實現(xiàn)無縫切換視屏的全部代碼了。
下面要說的坑才是重點:
①mediaplayer有個setNextMediaPlayer()方法棕诵,能設(shè)置下個播放的mediaplayer對象裁良,但是我試了很多次,都沒有辦法使用這個方法校套。
②我雖然實現(xiàn)了視頻的無縫切換价脾,但是mNextMediaPlayer對象播放出來的視頻始終與屏幕成90°,也就是說這種方法有很嚴重的bug的笛匙。只有在加載mNextMediaPlayer之前釋放mCurrentMediaPlayer對象的資源侨把,mNextMediaPlayer的視頻才能正確播放,然而這又無法實現(xiàn)視頻的無縫切換妹孙。
綜上秋柄,我這次嘗試失敗了。