您的位置:首页 > 移动开发 > Android开发

[置顶] Android播放器的三种实现方法

2018-02-28 10:39 429 查看
转载自:http://blog.csdn.net/wozuihaole/article/details/60867076今天来说一下Android中怎么实现视频播放,我主要说三种:1.MediaPlayer+SurfaceView;2.VideoView;3.Vitamio框架。
1.MediaPlayer+SurfaceView这种方法是基础,后面的两种方法其实就是把这种方法封装了一下,使用起来更方便些。我认为大家基本都会用MediaPlayer这个API,我们都知道MediaPlayer是媒体播放器,可以播放音频,视频其实就是给音频配上影像,而SurfaceView就是给音频配上影像的工具,我们只需要把SurfaceView与MediaPlayer关联起来就行了。主要代码:
SurfaceHolder holder = SurfaceView.getHolder();
MediaPlayer.setDisplay(holder);//将影像播放控件与媒体播放控件关联起来
我认为之前不知道的代码可能只有这两句。布局代码:

 效果图
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:con
1c135
text="com.example.video.MainActivity"
android:layout_margin="10dp"
android:orientation="vertical">

<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入文件名称例如:aa.mp4,务必确保文件放在sdcard目录下"/>

<SurfaceView
android:id="@+id/sfv"
android:layout_width="match_parent"
android:layout_marginTop="10dp"
android:layout_height="200dp" />

<SeekBar
android:id="@+id/sb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">

<Button
android:id="@+id/play"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_weight="1"
android:onClick="play"
android:text="播放"/>

<Button
android:id="@+id/pause"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:onClick="pause"
android:text="暂停"/>

<Button
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:onClick="stop"
android:text="停止"/>

<Button
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:onClick="replay"
android:text="重播"/>

</LinearLayout>

</LinearLayout>

完整代码+注释:package com.example.video;

import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

/**
* 需要注意的是我实验了.mp4,3gp和avi3种格式的视频,在5.1的真机和模拟器上avi格式都是只有声音没有影像,其他两种格式
* 播放正常。
*/

public class MainActivity extends Activity {

private SurfaceView sfv;//能够播放图像的控件
private SeekBar sb;//进度条
private String path ;//本地文件路径
private SurfaceHolder holder;
private MediaPlayer player;//媒体播放器
private Button Play;//播放按钮
private Timer timer;//定时器
private TimerTask task;//定时器任务
private int position = 0;
private EditText et;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initView();
}

//初始化控件,并且为进度条和图像控件添加监听
private void initView() {
sfv = (SurfaceView) findViewById(R.id.sfv);
sb = (SeekBar) findViewById(R.id.sb);
Play = (Button) findViewById(R.id.play);
et = (EditText) findViewById(R.id.et);
Play.setEnabled(false);

holder = sfv.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {

}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//当进度条停止拖动的时候,把媒体播放器的进度跳转到进度条对应的进度
if (player != null) {
player.seekTo(seekBar.getProgress());
}
}
});

holder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
//为了避免图像控件还没有创建成功,用户就开始播放视频,造成程序异常,所以在创建成功后才使播放按钮可点击
Log.d("zhangdi","surfaceCreated");
Play.setEnabled(true);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d("zhangdi","surfaceChanged");
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//当程序没有退出,但不在前台运行时,因为surfaceview很耗费空间,所以会自动销毁,
// 这样就会出现当你再次点击进程序的时候点击播放按钮,声音继续播放,却没有图像
//为了避免这种不友好的问题,简单的解决方式就是只要surfaceview销毁,我就把媒体播放器等
//都销毁掉,这样每次进来都会重新播放,当然更好的做法是在这里再记录一下当前的播放位置,
//每次点击进来的时候把位置赋给媒体播放器,很简单加个全局变量就行了。
Log.d("zhangdi","surfaceDestroyed");
if (player != null) {
position = player.getCurrentPosition();
stop();
}
}
});
}

private void play() {

Play.setEnabled(false);//在播放时不允许再点击播放按钮

if (isPause) {//如果是暂停状态下播放,直接start
isPause = false;
player.start();
return;
}

path = Environment.getExternalStorageDirectory().getPath()+"/";
path = path + et.getText().toString();//sdcard的路径加上文件名称是文件全路径
File file = new File(path);
if (!file.exists()) {//判断需要播放的文件路径是否存在,不存在退出播放流程
Toast.makeText(this,"文件路径不存在",Toast.LENGTH_LONG).show();
return;
}

try {
player = new MediaPlayer();
player.setDataSource(path);
player.setDisplay(holder);//将影像播放控件与媒体播放控件关联起来

player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {//视频播放完成后,释放资源
Play.setEnabled(true);
stop();
}
});

player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//媒体播放器就绪后,设置进度条总长度,开启计时器不断更新进度条,播放视频
Log.d("zhangdi","onPrepared");
sb.setMax(player.getDuration());
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
if (player != null) {
int time = player.getCurrentPosition();
sb.setProgress(time);
}
}
};
timer.schedule(task,0,500);
sb.setProgress(position);
player.seekTo(position);
player.start();
}
});

player.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}

public void play(View v) {
play();
Log.d("zhangdi",path);
}

private boolean isPause;
private void pause() {
if (player != null && player.isPlaying()) {
player.pause();
isPause = true;
Play.setEnabled(true);
}
}

public void pause(View v) {
pause();
}

private void replay() {
isPause = false;
if (player != null) {
stop();
play();
}
}

public void replay(View v) {
replay();
}

private void stop(){
isPause = false;
if (player != null) {
sb.setProgress(0);
player.stop();
player.release();
player = null;
if (timer != null) {
timer.cancel();
}
Play.setEnabled(true);
}
}

public void stop(View v) {
stop();
}

@Override
protected void onDestroy() {
super.onDestroy();
stop();
}
}

2.VideoView 系统自带的视频播放控件,自带进度条、暂停、播放等功能,使用起来十分简单,只需要为控件设置好播放路径,监听是否准备就绪,就绪后直接播放就可以了。

  效果图布局代码:<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main2"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.video.Main2Activity"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/et1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:hint="请输入文件名"/>

<Button
android:id="@+id/btn"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="确定"/>
</LinearLayout>

<VideoView
android:id="@+id/video"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginTop="10dp"/>

</LinearLayout>

完整代码:package com.example.video;

import android.app.Activity;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.MediaController;
import android.widget.VideoView;

import java.net.URI;

public class Main2Activity extends Activity {

private VideoView video;
private EditText et;
private Button btn;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);

initView();
}

private void initView() {
et = (EditText) findViewById(R.id.et1);
video = (VideoView) findViewById(R.id.video);
btn = (Button) findViewById(R.id.btn);

btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String path = Environment.getExternalStorageDirectory().getPath()+"/"+et.getText().toString();//获取视频路径
Uri uri = Uri.parse(path);//将路径转换成uri
video.setVideoURI(uri);//为视频播放器设置视频路径
video.setMediaController(new MediaController(Main2Activity.this));//显示控制栏
video.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
video.start();//开始播放视频
}
});
}
});
}
}

3.Vitamio 框架  使用起来和VideoView基本一样,区别在于,我们自己写的和系统自带的控件无法做到所有格式的视频都可以播放,但是这个框架基本可以实现,我用真机测试了mp4,flv,mkv,rmvb,3gp,avi这5中格式的视频,其中只有avi的只有声音没有影像,其他都可以正常播放,不过avi格式无法播放也可能是视频本身有点问题,不过我也没有其他视频了,无法继续测试,如果大家看完文章自己测试的时候可以用,也可以在回复的地方告诉我下,谢了。vitamio的library下载地址是:https://www.vitamio.org/Download/
效果图与2一样布局代码:<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main2"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.video.Main2Activity"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/et2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:hint="请输入文件名"/>

<Button
android:id="@+id/btn1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="确定"/>
</LinearLayout>

<io.vov.vitamio.widget.VideoView
android:id="@+id/video1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginTop="10dp"/>

</LinearLayout>

完整代码与2也一样,需要注意的是里面的VideoView是Vitamio中的,不是android.widget中的:package com.example.video;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import io.vov.vitamio.MediaPlayer;
import io.vov.vitamio.widget.MediaController;
import io.vov.vitamio.widget.VideoView;

public class Main3Activity extends Activity {

private VideoView video;
private Button btn;
private EditText et;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);

initView();
}

private void initView() {
video = (VideoView) findViewById(R.id.video1);
btn = (Button) findViewById(R.id.btn1);
et = (EditText) findViewById(R.id.et2);

btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String path = Environment.getExternalStorageDirectory().getPath()+"/"+et.getText().toString();
Uri uri = Uri.parse(path);
video.setVideoURI(uri);
video.setMediaController(new MediaController(Main3Activity.this));

video.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
video.start();
}
});
}
});
}
}

以上三种方法完整案例demo下载地址:下载地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: