Android实现视频播放的3种实现方式

Android实现视频播放的3种实现方式,第1张

概述Android提供了常见的视频的编码、解码机制。使用Android自带的MediaPlayer、MediaController等类可以很方便的实现视频播放的功能。支持的视频格式有MP4和3GP等。这些多媒体数据可以来自于Android应用的资源文件,也可以来自于外部存储器上的文件,甚至可以是来自于网络上的文件流。

AndroID提供了常见的视频的编码、解码机制。使用AndroID自带的MediaPlayer、MediaController等类可以很方便的实现视频播放的功能。支持的视频格式有MP4和3GP等。这些多媒体数据可以来自于AndroID应用的资源文件,也可以来自于外部存储器上的文件,甚至可以是来自于网络上的文件流。

下面来说一下视频播放的几种实现方式

1、MediaController+VIDeoVIEw实现方式
这种方式是最简单的实现方式。VIDeoVIEw继承了SurfaceVIEw同时实现了MediaPlayerControl接口,MediaController则是安卓封装的辅助控制器,带有暂停,播放,停止,进度条等控件。通过VIDeoVIEw+MediaController可以很轻松的实现视频播放、停止、快进、快退等功能。

布局文件如下:

<?xml version="1.0" enCoding="utf-8"?>
<androID.support.constraint.ConstraintLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"
xmlns:app="http://schemas.androID.com/apk/res-auto"
xmlns:tools="http://schemas.androID.com/tools"
androID:layout_wIDth="match_parent"
androID:layout_height="match_parent"
tools:context=".VIDeoVIEwTestActivity">
<VIDeoVIEw
androID:ID="@+ID/vIDeoVIEw"
androID:layout_wIDth="match_parent"
androID:layout_height="match_parent" />
</androID.support.constraint.ConstraintLayout>
程序代码如下:

public class VIDeoVIEwTestActivity extends AppCompatActivity {

@OverrIDe
protected voID onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentVIEw(R.layout.activity_vIDeo_vIEw_test);
VIDeoVIEw vIDeoVIEw = (VIDeoVIEw)findVIEwByID(R.ID.vIDeoVIEw);

//加载指定的视频文件
String path = Environment.getExternalStorageDirectory().getPath()+"/20180730.mp4";
vIDeoVIEw.setVIDeoPath(path);

//创建MediaController对象
MediaController mediaController = new MediaController(this);

//VIDeoVIEw与MediaController建立关联
vIDeoVIEw.setMediaController(mediaController);

//让VIDeoVIEw获取焦点
vIDeoVIEw.requestFocus();

}
}
使用此实现方式的步骤:

加载指定的视频文件
建立VIDeoVIEw和MediaController之间的关联,这样就不需要自己去控制视频的播放、暂停等。让MediaController控制即可。
VIDeoVIEw获取焦点。
实现效果图如下:

 

界面中的快退、播放、快进、时间、进度条等是由MediaController提供的。

2、MediaPlayer+SurfaceVIEw+自定义控制器
虽然VIDeoVIEw的实现方式很简单,但是由于是自带的封装好的类,所以无论是播放器的大小、位置以及控制都不受我们控制。

这种实现方式步骤如下:

创建MediaPlayer对象,并让它加载指定的视频文件。可以是应用的资源文件、本地文件路径、或者URL。
在界面布局文件中定义SurfaceVIEw组件,并为SurfaceVIEw的SurfaceHolder添加Callback监听器。
调用MediaPlayer对象的setdisplay(SurfaceHolder sh)将所播放的视频图像输出到指定的SurfaceVIEw组件。
调用MediaPlayer对象的prepareAsync()或prepare()方法装载流媒体文件
调用MediaPlayer对象的start()、stop()和pause()方法来控制视频的播放。
在实现第二步之前需要先给surfaceHolder设置一个callback,callback的3个回调函数如下:

@OverrIDe
public voID surfaceCreated(SurfaceHolder holder) {
}

@OverrIDe
public voID surfaceChanged(SurfaceHolder holder, int format, int wIDth, int height) {

}

@OverrIDe
public voID surfaceDestroyed(SurfaceHolder holder) {

}
布局文件如下:

<?xml version="1.0" enCoding="utf-8"?>
<androID.support.constraint.ConstraintLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"
xmlns:app="http://schemas.androID.com/apk/res-auto"
xmlns:tools="http://schemas.androID.com/tools"
androID:layout_wIDth="match_parent"
androID:layout_height="match_parent"
tools:context=".PlayVIDeoActivity">

<relativeLayout
androID:ID="@+ID/root_rl"
androID:layout_wIDth="match_parent"
androID:layout_height="400dp"
androID:background="#000000">

<SurfaceVIEw
androID:ID="@+ID/surfaceVIEw"
androID:layout_wIDth="match_parent"
androID:layout_height="400dp" />
<ImageVIEw
androID:ID="@+ID/playOrPause"
androID:layout_wIDth="60dp"
androID:layout_height="60dp"
androID:layout_centerInParent="true"
androID:src="@androID:drawable/ic_media_play"/>
<linearLayout
androID:ID="@+ID/control_ll"
androID:layout_wIDth="match_parent"
androID:layout_height="wrap_content"
androID:layout_alignParentBottom="true"
androID:background="#005500"
androID:orIEntation="vertical">

<relativeLayout
androID:layout_wIDth="match_parent"
androID:layout_height="wrap_content"
androID:layout_marginleft="10dp"
androID:layout_marginRight="10dp"
androID:orIEntation="horizontal"
androID:paddingBottom="5dp">

<TextVIEw
androID:ID="@+ID/tv_start_time"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:layout_alignParentleft="true"
androID:layout_marginleft="30dp"
androID:text="00.00"
androID:textcolor="#ffffff"/>
<TextVIEw
androID:ID="@+ID/tv_separate_time"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:layout_toRightOf="@+ID/tv_start_time"
androID:layout_marginleft="1dp"
androID:text="/"
androID:textcolor="#ffffff"/>
<TextVIEw
androID:ID="@+ID/tv_end_time"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:layout_toRightOf="@+ID/tv_separate_time"
androID:layout_marginleft="1dp"
androID:text="00.00"
androID:textcolor="#ffffff"/>
<ImageVIEw
androID:ID="@+ID/tv_backward"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:layout_below="@+ID/tv_start_time"
androID:layout_alignParentleft="true"
androID:layout_marginleft="1dp"
androID:src="@androID:drawable/ic_media_rew"/>

<Seekbar
androID:ID="@+ID/tv_progess"
androID:layout_wIDth="match_parent"
androID:layout_height="wrap_content"
androID:layout_toRightOf="@+ID/tv_backward"
androID:layout_toleftOf="@+ID/tv_forward"
androID:layout_below="@+ID/tv_start_time"/>

<ImageVIEw
androID:ID="@+ID/tv_forward"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:layout_below="@+ID/tv_start_time"
androID:layout_alignParentRight="true"
androID:layout_marginRight="1dp"
androID:src="@androID:drawable/ic_media_ff"/>

</relativeLayout>

</linearLayout>
</relativeLayout>

</androID.support.constraint.ConstraintLayout>
程序代码如下:

public class PlayVIDeoActivity extends AppCompatActivity implements SurfaceHolder.Callback,
MediaPlayer.OnPreparedListener,
MediaPlayer.OnCompletionListener,
MediaPlayer.OnErrorListener,
MediaPlayer.OnInfoListener, VIEw.OnClickListener,
MediaPlayer.OnSeekCompleteListener,
MediaPlayer.OnVIDeoSizeChangedListener,
Seekbar.OnSeekbarchangelistener,
{

private ImageVIEw playOrPauseIv;
private SurfaceVIEw vIDeoSuf;
private MediaPlayer mPlayer;
private Seekbar mSeekbar;
private String path;
private relativeLayout rootVIEwRl;
private linearLayout controlLl;
private TextVIEw startTime, endTime;
private ImageVIEw forwardbutton, backwardbutton;
private boolean isShow = false;

public static final int UPDATE_TIME = 0x0001;
public static final int HIDE_CONTRol = 0x0002;

private Handler mHandler = new Handler() {
@OverrIDe
public voID handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TIME:
updateTime();
mHandler.sendEmptyMessageDelayed(UPDATE_TIME, 500);
break;
case HIDE_CONTRol:
hIDeControl();
break;
}
}
};
@OverrIDe
protected voID onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentVIEw(R.layout.activity_play_vIDeo);
initVIEws();
initData();
initSurfaceVIEw();
initPlayer();
initEvent();
}
private voID initData() {
path = Environment.getExternalStorageDirectory().getPath() + "/20180730.mp4";//这里写上你的视频地址
}

private voID initEvent() {
playOrPauseIv.setonClickListener(this);
rootVIEwRl.setonClickListener(this);
rootVIEwRl.setontouchListener(this);
forwardbutton.setonClickListener(this);
backwardbutton.setonClickListener(this);
mSeekbar.setonSeekbarchangelistener(this);
}
private voID initSurfaceVIEw() {
vIDeoSuf = (SurfaceVIEw) findVIEwByID(R.ID.surfaceVIEw);
vIDeoSuf.setZOrderOntop(false);
vIDeoSuf.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
vIDeoSuf.getHolder().addCallback(this);
}

private voID initPlayer() {
mPlayer = new MediaPlayer();
mPlayer.setonCompletionListener(this);
mPlayer.setonErrorListener(this);
mPlayer.setonInfoListener(this);
mPlayer.setonPreparedListener(this);
mPlayer.setonSeekCompleteListener(this);
mPlayer.setonVIDeoSizeChangedListener(this);
try {
//使用手机本地视频
mPlayer.setDataSource(path);
} catch (Exception e) {
e.printstacktrace();
}
}

private voID initVIEws() {
playOrPauseIv = (ImageVIEw) findVIEwByID(R.ID.playOrPause);
startTime = (TextVIEw) findVIEwByID(R.ID.tv_start_time);
endTime = (TextVIEw) findVIEwByID(R.ID.tv_end_time);
mSeekbar = (Seekbar) findVIEwByID(R.ID.tv_progess);
rootVIEwRl = (relativeLayout) findVIEwByID(R.ID.root_rl);
controlLl = (linearLayout) findVIEwByID(R.ID.control_ll);
forwardbutton = (ImageVIEw) findVIEwByID(R.ID.tv_forward);
backwardbutton = (ImageVIEw) findVIEwByID(R.ID.tv_backward);
}

@OverrIDe
public voID surfaceCreated(SurfaceHolder holder) {
mPlayer.setdisplay(holder);
mPlayer.prepareAsync();
}

@OverrIDe
public voID surfaceChanged(SurfaceHolder holder, int format, int wIDth, int height) {

}

@OverrIDe
public voID surfaceDestroyed(SurfaceHolder holder) {

}
@OverrIDe
public voID onPrepared(MediaPlayer mp) {
startTime.setText(FormatTimeUtil.formatLongToTimeStr(mp.getCurrentposition()));
endTime.setText(FormatTimeUtil.formatLongToTimeStr(mp.getDuration()));
mSeekbar.setMax(mp.getDuration());
mSeekbar.setProgress(mp.getCurrentposition());
}
@OverrIDe
public voID onCompletion(MediaPlayer mp) {

}
@OverrIDe
public boolean one rror(MediaPlayer mp, int what, int extra) {
return false;
}

@OverrIDe
public boolean onInfo(MediaPlayer mp, int what, int extra) {
return false;
}
private voID play() {
if (mPlayer == null) {
return;
}
Log.i("playPath", path);
if (mPlayer.isPlaying()) {
mPlayer.pause();
mHandler.removeMessages(UPDATE_TIME);
mHandler.removeMessages(HIDE_CONTRol);
playOrPauseIv.setVisibility(VIEw.VISIBLE);
playOrPauseIv.setimageResource(androID.R.drawable.ic_media_play);
} else {
mPlayer.start();
mHandler.sendEmptyMessageDelayed(UPDATE_TIME, 500);
mHandler.sendEmptyMessageDelayed(HIDE_CONTRol, 5000);
playOrPauseIv.setVisibility(VIEw.INVISIBLE);
playOrPauseIv.setimageResource(androID.R.drawable.ic_media_pause);
}
}
@OverrIDe
public voID onSeekComplete(MediaPlayer mp) {
//Todo
}

@OverrIDe
public voID onVIDeoSizeChanged(MediaPlayer mp, int wIDth, int height) {

}
@OverrIDe
public voID onClick(VIEw v) {
switch (v.getID()) {
case R.ID.tv_backward:
backWard();
break;
case R.ID.tv_forward:
forWard();
break;
case R.ID.playOrPause:
play();
break;
case R.ID.root_rl:
showControl();
break;
}
}
/**
* 更新播放时间
*/
private voID updateTime() {

startTime.setText(FormatTimeUtil.formatLongToTimeStr(
mPlayer.getCurrentposition()));
mSeekbar.setProgress(mPlayer.getCurrentposition());
}

/**
* 隐藏进度条
*/
private voID hIDeControl() {
isShow = false;
mHandler.removeMessages(UPDATE_TIME);
controlLl.animate().setDuration(300).translationY(controlLl.getHeight());
}
/**
* 显示进度条
*/
private voID showControl() {
if (isShow) {
play();
}
isShow = true;
mHandler.removeMessages(HIDE_CONTRol);
mHandler.sendEmptyMessage(UPDATE_TIME);
mHandler.sendEmptyMessageDelayed(HIDE_CONTRol, 5000);
controlLl.animate().setDuration(300).translationY(0);
}
/**
* 设置快进10秒方法
*/
private voID forWard(){
if(mPlayer != null){
int position = mPlayer.getCurrentposition();
mPlayer.seekTo(position + 10000);
}
}

/**
* 设置快退10秒的方法
*/
public voID backWard(){
if(mPlayer != null){
int position = mPlayer.getCurrentposition();
if(position > 10000){
position-=10000;
}else{
position = 0;
}
mPlayer.seekTo(position);
}
}

//OnSeekbarchangelistener
@OverrIDe
public voID onProgressChanged(Seekbar seekbar, int progress, boolean b) {
if(mPlayer != null && b){
mPlayer.seekTo(progress);
}
}

@OverrIDe
public voID onStartTrackingtouch(Seekbar seekbar) {
}

@OverrIDe
public voID onStopTrackingtouch(Seekbar seekbar) {

}
}
注意事项:MediaPlayer有prepare和prepareAsync两种方法。这两种方法的区别是:prepare方法是将资源同步缓存到内存中,一般加载本地较小的资源可以用这个,如果是较大的资源或者网络资源建议使用prepareAsync方法,异步加载。

实现效果如下所示:

 

3、MediaPlayer+SurfaceVIEw+MediaController
第二种实现方式使用的是自定义控件,MediaPlayer+SurfaceVIEw也可以使用系统自带的MediaController控制器。

使用这个方式实现,布局文件只需一个SurfaceVIEw即可,其他的控件都交给MediaController控制器,布局文件如下:

<?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:layout_wIDth="match_parent"
androID:layout_height="match_parent"
tools:context=".MediaControllerTestActivity"
androID:ID="@+ID/root_ll">
<SurfaceVIEw
androID:layout_wIDth="match_parent"
androID:layout_height="match_parent"
androID:ID="@+ID/controll_surfaceVIEw"/>
</linearLayout>
程序代码如下:

public class MediaControllerTestActivity extends Activity implements
MediaController.MediaPlayerControl,
MediaPlayer.OnBufferingUpdateListener,
SurfaceHolder.Callback{
private MediaPlayer mediaPlayer;
private MediaController controller;
private int bufferPercentage = 0;
@OverrIDe
protected voID onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentVIEw(R.layout.activity_media_controller_test);
mediaPlayer = new MediaPlayer();
controller = new MediaController(this);
controller.setAnchorVIEw(findVIEwByID(R.ID.root_ll));
initSurfaceVIEw();
}

private voID initSurfaceVIEw() {
SurfaceVIEw vIDeoSuf = (SurfaceVIEw) findVIEwByID(R.ID.controll_surfaceVIEw);
vIDeoSuf.setZOrderOntop(false);
vIDeoSuf.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
vIDeoSuf.getHolder().addCallback(this);
}
@OverrIDe
protected voID onResume() {
super.onResume();
try {
String path = Environment.getExternalStorageDirectory().getPath() + "/20180730.mp4";
mediaPlayer.setDataSource(path);
mediaPlayer.setonBufferingUpdateListener(this);
//mediaPlayer.prepare();

controller.setMediaPlayer(this);
controller.setEnabled(true);

}catch (IOException e){
e.printstacktrace();
}
}

@OverrIDe
protected voID onPause() {
super.onPause();
if (mediaPlayer.isPlaying()){
mediaPlayer.stop();
}
}

@OverrIDe
protected voID onDestroy() {
super.onDestroy();
if (null != mediaPlayer){
mediaPlayer.release();
mediaPlayer = null;
}
}

@OverrIDe
public boolean ontouchEvent(MotionEvent event) {
controller.show();
return super.ontouchEvent(event);
}

//MediaPlayer
@OverrIDe
public voID onPointerCaptureChanged(boolean hasCapture) {

}
//MediaPlayerControl
@OverrIDe
public voID onBufferingUpdate(MediaPlayer mediaPlayer, int i) {
bufferPercentage = i;
}

@OverrIDe
public voID start() {
if (null != mediaPlayer){
mediaPlayer.start();
}
}

@OverrIDe
public voID pause() {
if (null != mediaPlayer){
mediaPlayer.pause();
}
}

@OverrIDe
public int getDuration() {
return mediaPlayer.getDuration();
}

@OverrIDe
public int getCurrentposition() {
return mediaPlayer.getCurrentposition();
}

@OverrIDe
public voID seekTo(int i) {
mediaPlayer.seekTo(i);
}

@OverrIDe
public boolean isPlaying() {
if (mediaPlayer.isPlaying()){
return true;
}
return false;
}

@OverrIDe
public int getBufferPercentage() {
return bufferPercentage;
}

@OverrIDe
public boolean canPause() {
return true;
}

@OverrIDe
public boolean canSeekBackward() {
return true;
}

@OverrIDe
public boolean canSeekForward() {
return true;
}

@OverrIDe
public int getAudioSessionID() {
return 0;
}

//SurfaceHolder.callback
@OverrIDe
public voID surfaceCreated(SurfaceHolder surfaceHolder) {
mediaPlayer.setdisplay(surfaceHolder);
mediaPlayer.prepareAsync();
}

@OverrIDe
public voID surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

}

@OverrIDe
public voID surfaceDestroyed(SurfaceHolder surfaceHolder) {

}
}
效果图如下:


————————————————
版权声明:本文为CSDN博主「若尘风」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/liuzhi0724/article/details/81318816

总结

以上是内存溢出为你收集整理的Android实现视频播放的3种实现方式全部内容,希望文章能够帮你解决Android实现视频播放的3种实现方式所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1033344.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)

保存