上篇文章中主要是介绍MediaPlay状态机流程和API的详解。同时也实现了一个简单的音频播放器,下面我们就来利用SurfaceView+MediaPlay实现一个简单的视频播放器。
视频播放器的效果如下所示:
`
1、创建一个MyVideoPlayer .java类,这个类主要是结合MediaPlayer对视频的播放、暂停、停止、继续播放等功能处理
public class MyVideoPlayer implements MediaPlayer.OnPreparedListener{
private static final String TAG = "MyVideoPlayer";
private String path = "/storage/emulated/0/aatest/demo.mp4";
private boolean isInitFinish = false;
private boolean isSeekbarChaning;
private Timer timer;//定时器
private MediaPlayer mediaPlayer;
private boolean isStop = false;
public MyVideoPlayer(){
initMediaPlayer();
}
private void initMediaPlayer() {
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(path);//
//mediaPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT);//缩放模式
mediaPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
mediaPlayer.setLooping(false);//设置循环播放
mediaPlayer.prepareAsync();//异步准备
//当装载流媒体完毕的时候回调。
mediaPlayer.setOnPreparedListener(this);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 给mMediaPlayer添加预览的SurfaceHolder
* @param holder
*/
public void setDisplay(SurfaceHolder holder){
mediaPlayer.setDisplay(holder);
}
public void playVide(final SeekBar seekbar){
if(mediaPlayer != null) {
mediaPlayer.start();
int duration = mediaPlayer.getDuration();//获取音乐总时间
seekbar.setMax(duration);//将音乐总时间设置为Seekbar的最大值
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if(!isSeekbarChaning){
if(!isStop){
seekbar.setProgress(mediaPlayer.getCurrentPosition());
}
}
}
},0,50);
}
}
/**
* 互斥变量,防止进度条和定时器冲突
* @param isSeekbar
*/
public void setSeekbarChaning(boolean isSeekbar){
isSeekbarChaning = isSeekbar;
}
/**
* 获取Seekbar状态
* @return
*/
public boolean isSeekbarChaning(){
return isSeekbarChaning;
}
/**
* 暂停播放
*/
public void pausePlay(){
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
/**
* 重新播放
*/
public void replayPlay(){
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(0);
isStop = false;
}
}
/**
* 停止播放
*/
public void stopPlay(){
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
isStop = true;
mediaPlayer.stop();
mediaPlayer.prepareAsync();
//mediaPlayer.release();
//mediaPlayer = null;
}
}
/**
*循环播放
* @param looping
*/
public void setLooping(boolean looping){
mediaPlayer.setLooping(looping);
}
/**
* 获取总时长
* @return
*/
public int getDuration(){
int duration = mediaPlayer.getDuration();
return duration;
}
/**
* 获取当前播放的位置
* @return
*/
public int getCurrentPosition(){
int currentPosition = mediaPlayer.getCurrentPosition();
return currentPosition;
}
/**
* 设置当前MediaPlayer的播放位置,单位是毫秒
* @param progress
*/
public void setSeekto(int progress){
mediaPlayer.seekTo(progress);//在当前位置播放
}
/**
* 释放资源
*/
public void release(){
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
//回收流媒体资源
mediaPlayer.release();
mediaPlayer = null;
}
}
/**
* 传入的数据为毫秒数
* @param time
* @return
*/
public String formattime(long time){
String min= (time/(1000*60))+"";
String second= (time%(1000*60)/1000)+"";
if(min.length()<2){
min=0+min;
}
if(second.length()<2){
second=0+second;
}
return min+":"+second;
}
/**
* 计算播放时间
* @param time
* @return
*/
public String calculateTime(int time){
int minute;
int second;
if(time > 60){
minute = time / 60;
second = time % 60;
//分钟再0~9
if(minute >= 0 && minute < 10){
//判断秒
if(second >= 0 && second < 10){
return "0"+minute+":"+"0"+second;
}else {
return "0"+minute+":"+second;
}
}else {
//分钟大于10再判断秒
if(second >= 0 && second < 10){
return minute+":"+"0"+second;
}else {
return minute+":"+second;
}
}
}else if(time < 60){
second = time;
if(second >= 0 && second < 10){
return "00:"+"0"+second;
}else {
return "00:"+ second;
}
}
return null;
}
@Override
public void onPrepared(MediaPlayer mp) {
isInitFinish = true;
}
}
2、新建VideoActivity .java类处理UI
public class VideoActivity extends AppCompatActivity {
private static final String TAG = "VideoActivity";
private MyVideoPlayer myVideoPlayer;
private SurfaceView mVideoPlaySurfaceview;
private SurfaceHolder mSurfaceHolder;
private TextView tv_end;
private SeekBar seekbar;
private TextView tv_start;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);
PermissionsManagement.requestMyPermissions(this);
seekbar = (SeekBar)findViewById(R.id.seekbar);
tv_end = (TextView)findViewById(R.id.tv_end);
tv_start = (TextView)findViewById(R.id.tv_start);
myVideoPlayer = new MyVideoPlayer();
initSurfaceview();
}
private void initSurfaceview() {
mVideoPlaySurfaceview = findViewById(R.id.video_surfaceview);
mSurfaceHolder = mVideoPlaySurfaceview.getHolder();
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
myVideoPlayer.setDisplay(holder);//给mMediaPlayer添加预览的SurfaceHolder
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e(TAG, "surfaceChanged触发: width=" + width + "height" + height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
//绑定监听器,监听拖动到指定位置
seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int duration2 = myVideoPlayer.getDuration() / 1000;//获取音乐总时长
int position = myVideoPlayer.getCurrentPosition();//获取当前播放的位置
tv_start.setText(myVideoPlayer.calculateTime(position / 1000));//开始时间
tv_end.setText(myVideoPlayer.calculateTime(duration2));//总时长
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
myVideoPlayer.setSeekbarChaning(true);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
myVideoPlayer.setSeekbarChaning(false);
myVideoPlayer.setSeekto(seekBar.getProgress());//在当前位置播放
tv_start.setText(myVideoPlayer.formattime(myVideoPlayer.getCurrentPosition()));
}
});
int duration2 = myVideoPlayer.getDuration() / 1000;//获取音乐总时长
int position = myVideoPlayer.getCurrentPosition();//获取当前播放的位置
tv_start.setText(myVideoPlayer.calculateTime(position / 1000));//开始时间
tv_end.setText(myVideoPlayer.calculateTime(duration2));//总时长
}
@Override
protected void onDestroy() {
super.onDestroy();
myVideoPlayer.release();
}
/**
* 播放视频
* @param view
*/
public void onPlayVide(View view) {
myVideoPlayer.playVide(seekbar);
}
/**
* 暂停播放
* @param view
*/
public void onPauseVide(View view) {
myVideoPlayer.pausePlay();
}
/**
* 重新播放
* @param view
*/
public void onReplayVide(View view) {
myVideoPlayer.replayPlay();
}
/**
* 循环播放
* @param view
*/
public void onLoopingVide(View view) {
myVideoPlayer.setLooping(true);
}
/**
* 停止播放
* @param view
*/
public void onStopVide(View view) {
myVideoPlayer.stopPlay();
}
}
2、新建一个布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/video_surfaceview"
android:layout_width="wrap_content"
android:layout_height="250dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_marginTop="20dp"
android:layout_height="wrap_content">
<TextView
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_start" />
<SeekBar
android:layout_width="250dp"
android:layout_height="wrap_content"
android:id="@+id/seekbar" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_end" />
</LinearLayout>
<Button
android:layout_width="match_parent"
android:onClick="onPlayVide"
android:text="播放"
android:layout_height="wrap_content"/>
<Button
android:layout_width="match_parent"
android:onClick="onPauseVide"
android:text="暂停"
android:layout_height="wrap_content"/>
<Button
android:layout_width="match_parent"
android:onClick="onReplayVide"
android:text="重新播放"
android:layout_height="wrap_content"/>
<Button
android:layout_width="match_parent"
android:onClick="onLoopingVide"
android:text="循环播放"
android:layout_height="wrap_content"/>
<Button
android:layout_width="match_parent"
android:onClick="onStopVide"
android:text="停止播放"
android:layout_height="wrap_content"/>
</LinearLayout>