Android 多媒體應用:視訊播放之VideoView與SurfaceView
實際上我們這裡所說的VideoView與SurfaceView並不適用於我們真正的實際開發中,那麼我們為什麼還要學習他們呢?在實際開發中我們又該如何使用什麼呢?
一、為什麼要學習VideoView與SurfaceView
在思考為什麼學習VideoView與SurfaceView之前,先想一下為什麼不適合實際開發,這是因為VideoView並不是支援播放所有格式的視訊,它僅支援mp4和3gp格式的檔案,實際上它的本質是SurfaceView+MediaPlayer的封裝。而SurfaceView一般是用於遊戲,它不適用的原因有兩個,一是它支援視訊播放的格式有限,二是在播放視訊的時候消耗的系統記憶體比較大。但由於它是Android自身提供的,作為一種基礎,我們還是有必要學習一下的。在實際開發中可以使用的Vitamio和FFMPEG。
這裡要說明一下,如果想要做專門的視訊方面的軟體我們僅僅學會如何使用第三方類庫是不夠的,還需要學習流媒體視訊的解碼與編碼方面的知識,如果僅是在應用軟體中進行呼叫就學會使用第三方就足夠了。
二、VideoView
首先來了解一下VideoView,VideoView是Android自身為我們提供的視訊播放的元件,但是它僅支援播放mp4和3gp格式的檔案,能播放的視訊檔案格式非常少。
1、使用步驟(只需要三步)
(1)在佈局中新增VideoView
(2)在MainActivity中進行設定setVideoPath()、setMediaplayerController()(VideoView自帶的控制進度條)
(3)start()即可
佈局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height ="wrap_content"
android:text="開始"/>
<VideoView
android:id="@+id/videoview"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"/>
</LinearLayout>
MainActivity
mvideoview.setVideoPath(Environment.getExternalStorageDirectory()+"/aa.mp4");
mvideoview.setMediaController(new MediaController(MainActivity.this));
mvideoview.start();
三、SurfaceView
SurfaceView介紹
1、關於SurfaceView內部機制
2、SurfaceView具有雙緩衝技術,該技術不是Android特有的而是早就有的,那麼什麼是雙緩衝呢?以前無雙緩衝的UI重新整理是先將介面清除再進行繪製介面,這樣做會有弊端,容易出現白屏,白屏出現次數多的話容易讓使用者看到閃屏,而雙緩衝則是已經存在了兩個介面,想要重新整理介面時,直接將另一個介面覆蓋在該介面上面,隱藏的介面就會在系統的記憶體中擦掉頁面,衝新繪製,由於沒有在螢幕進行擦除頁面,因此不會出現白屏。
3、SurfaceView是一個重量級元件,因此Surfaceview只要不可見就不會建立,只有可見的時候才能執行;只要不可見就被銷燬。注:如果直接在介面上寫SurfaceView,一開啟應用就讓它播放,是不能播放的,這是因為它還沒有被建立好,不能直接使用。
SurfaceView使用
SurfaceView的使用是與MediaPlayer結合使用的,向MediaPlayer中放置一個SurfaceHolder物件。
(1)在佈局中進行新增SurfaceView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<SurfaceView
android:id="@+id/surface"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
<Button
android:id="@+id/btn_start_surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="開始播放" />
</LinearLayout>
(2)建立Mediaplayer+SurfaceView
public class Activity_SurfaceView extends Activity implements OnClickListener{
private Button mbtn_start_sur;
private SurfaceView msurfaceview;
private MediaPlayer player;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.surfaceview);
mbtn_start_sur=(Button) findViewById(R.id.btn_start_surface);
msurfaceview=(SurfaceView) findViewById(R.id.surface);
mbtn_start_sur.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start_surface:
if(player==null){
//建立MediaPlayer物件
player=new MediaPlayer();
}
try {
//設定播放檔案的地址
player.setDataSource(Environment.getExternalStorageDirectory()+"/aa.mp4");
//設定聲音播放模式
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
//設定顯示位置,這裡要使用SurfaceHolder player.setDisplay(msurfaceview.getHolder());
player.prepare();
player.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
default:
break;
}
}
}
SurfaceView的播視訊示例
佈局中只有一個SurfaceView,由於SurfaceView的建立需要時間,在不可將的時候又不會建立,如果直接播放,這裡就會出現問題,視訊不會自動播放,想要在它上面播放視訊,必須對它進行監聽,但是它又沒有監聽器,所以呼叫了它的SurfaceHolder的addCallback進行監聽。
功能實現:
點選home或者back鍵,視訊停止播放,再次開啟應用,視訊從上次位置開始播放。
public class Activity_SurfaceView extends Activity {
private SurfaceView msurfaceview;
private MediaPlayer player;
private int currentposition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.surfaceview);
msurfaceview=(SurfaceView) findViewById(R.id.surface);
final SurfaceHolder sh=msurfaceview.getHolder();
sh.addCallback(new Callback() {
//SurfaceView建立時呼叫
//監聽SurfaceView可見的時候播放,我們在這裡進行監聽
//每次開始播放時才進行播放,每次開啟應用都會建立SurfaceView(SurceView不可見就會被銷燬的原因)
@Override
public void surfaceCreated(SurfaceHolder holder) {
//播放視訊的是Mediaplayer,不進行判斷,點選back鍵,然後再進入應用時Player會被再次建立
if(player==null){
player=new MediaPlayer();
}
try {
player.setDataSource(Environment.getExternalStorageDirectory()+"/aa.mp4");
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDisplay(sh);
player.prepare();
player.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
//從上次銷燬位置開始播放,而不是從頭播放
mp.seekTo(currentposition);
}
});
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
//SurfaceView銷燬時呼叫
//每次SurfaceView停止時就停止播放視訊,我們在這裡進行設定的原因是
//如果不進行設定點選back鍵時視訊仍在播放,再開啟的應用的時候視訊會出現問題
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if(player!=null){
//記錄當前位置,在點選home或者back再次進入時還是可以從上次位置開始播放
currentposition=player.getCurrentPosition();
//不停止的話,點選back,視訊仍會在播放
player.stop();
player.release();
player=null;
}
}
});
}