使用SurfaceView控件+MediaPlayer类播放视频的主要原理是把MediaPlayer对象的显示控件设置为SurfaceView对象。播放控制都是针对MediaPlayer对象,用法与播放音频相同。主要流程和对应的代码如下图:
播放视频的流程只是比播放音频多了设置显示控件一步。
下面编写一个用SurfaceView+MediaPlayer播放视频的例子。例子使用资源ID方式作为MediaPlayer的视频源,所以需将视频文件demo.mp4复制到项目的res/raw目录下。应用的界面和对应的主要代码如下:
为MediaPlayer设置显示控件时需要注意:不能在onCreate中设置,因为SurfaceView控件还未准备好,需要延迟一段时间再设置。因此,这个例子中在PLAY按钮按下时再设置。
要通过下面的语句设置视频分辨率,不然会根据窗口尺寸拉伸:
surfaceView.getHolder().setFixedSize(1080, 720);
视频显示尺寸(1080, 720)是根据SurfaceView在界面上尺寸和视频实际尺寸(640, 360)计算得出。
播放控制都是针对MediaPlayer对象,用法与播放音频相同。例子中还用SeekBar控件来显示播放进度,控制播放位置。
例子的完整代码如下:
public class MainActivity extends AppCompatActivity {
SurfaceView surfaceView;
MediaPlayer player;
SeekBar seekBar;
Handler handler;
Runnable runnable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
setContentView(ll);
Button btnPlay = new Button(this);
btnPlay.setText("Play");
ll.addView(btnPlay);
btnPlay.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View arg0) {
player.setDisplay(surfaceView.getHolder());
player.start();
startTimer();
}
});
Button btnStop = new Button(this);
btnStop.setText("Stop");
ll.addView(btnStop);
btnStop.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View arg0) {
//player.stop(); // stop后player对象不能再播放
player.pause();
player.seekTo(0);
stopTimer();
}
});
Button btnPause = new Button(this);
btnPause.setText("Pause");
ll.addView(btnPause);
btnPause.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View arg0) {
if(player.isPlaying()){
player.pause();
stopTimer();
((Button)arg0).setText("Continue");
} else {
player.start();
startTimer();
((Button)arg0).setText("Pause");
}
}
});
Button btnReset = new Button(this);
btnReset.setText("Reset");
ll.addView(btnReset);
btnReset.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View arg0) {
//player.reset(); // reset后需要重新设置视频来源
player.seekTo(0);
}
});
player = MediaPlayer.create(this, R.raw.demo);
surfaceView = new SurfaceView(this);
surfaceView.getHolder().setFixedSize(1080, 720);
//player.setDisplay(surfaceView.getHolder()); // 不能在此设置,因为surfaceView还未准备好,在play按钮按下时再设置即可
ll.addView(surfaceView);
seekBar = new SeekBar(this);
seekBar.setMax(100);
ll.addView(seekBar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
@Override
public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
}
@Override
public void onStopTrackingTouch(SeekBar arg0) {
int pos = seekBar.getProgress() * player.getDuration() / seekBar.getMax();
player.seekTo(pos);
}
});
player.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
@Override
public void onCompletion(MediaPlayer arg0) {
stopTimer();
}
});
initTimer();
}
protected void onDestroy(){
super.onDestroy();
stopTimer();
player.release();
}
void initTimer(){
handler = new Handler();
runnable = new Runnable(){
@Override
public void run() {
int d = player.getDuration();
int p = player.getCurrentPosition();
seekBar.setProgress(p*seekBar.getMax()/d);
handler.postDelayed(runnable, 1000);
}
};
}
void startTimer(){
handler.postDelayed(runnable, 1000);
}
void stopTimer(){
handler.removeCallbacks(runnable);
}
}
例子中用到的主要的类有SurfaceView、MediaPlayer,接口有SurfaceHolder。
用到的SurfaceView类的方法有:
- 构造函数SurfaceView(Context context),通过Context创建SurfaceView对象。
- SurfaceHolder getHolder (),得到SurfaceHolder对象用于管理SurfaceView
用到的MediaPlayer类的新的方法是:
- void setDisplay(SurfaceHolder sh),用于设置显示视频的UI控件SurfaceHolder。
用到的SurfaceHolder接口的方法有:
- void setFixedSize(int width, int height),设置视频尺寸,用视频的实际尺寸即可
- void setKeepScreenOn(boolean screenOn),设置视频播放时是否保持屏幕常亮
完整代码下载: