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"><VideoViewandroid:id="@+id/videoView"android:layout_width="match_parent"android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>

程序代码如下:

public class VideoViewTestActivity extends AppCompatActivity {@Overrideprotected 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();}
}

使用此实现方式的步骤:

  1. 加载指定的视频文件
  2. 建立VideoView和MediaController之间的关联,这样就不需要自己去控制视频的播放、暂停等。让MediaController控制即可。
  3. VideoView获取焦点。

实现效果图如下:

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

2、MediaPlayer+SurfaceView+自定义控制器

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

这种实现方式步骤如下:

  1. 创建MediaPlayer对象,并让它加载指定的视频文件。可以是应用的资源文件、本地文件路径、或者URL。
  2. 在界面布局文件中定义SurfaceView组件,并为SurfaceView的SurfaceHolder添加Callback监听器。
  3. 调用MediaPlayer对象的setDisplay(SurfaceHolder sh)将所播放的视频图像输出到指定的SurfaceView组件。
  4. 调用MediaPlayer对象的prepareAsync()或prepare()方法装载流媒体文件
  5. 调用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"><RelativeLayoutandroid:id="@+id/root_rl"android:layout_width="match_parent"android:layout_height="400dp"android:background="#000000"><SurfaceViewandroid:id="@+id/surfaceView"android:layout_width="match_parent"android:layout_height="400dp" /><ImageViewandroid:id="@+id/playOrPause"android:layout_width="60dp"android:layout_height="60dp"android:layout_centerInParent="true"android:src="@android:drawable/ic_media_play"/><LinearLayoutandroid:id="@+id/control_ll"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:background="#005500"android:orientation="vertical"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:orientation="horizontal"android:paddingBottom="5dp"><TextViewandroid: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"/><TextViewandroid: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"/><TextViewandroid: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"/><ImageViewandroid: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"/><SeekBarandroid: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"/><ImageViewandroid: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() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case UPDATE_TIME:updateTime();mHandler.sendEmptyMessageDelayed(UPDATE_TIME, 500);break;case HIDE_CONTROL:hideControl();break;}}};@Overrideprotected 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);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {mPlayer.setDisplay(holder);mPlayer.prepareAsync();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}@Overridepublic void onPrepared(MediaPlayer mp) {startTime.setText(FormatTimeUtil.formatLongToTimeStr(mp.getCurrentPosition()));endTime.setText(FormatTimeUtil.formatLongToTimeStr(mp.getDuration()));mSeekBar.setMax(mp.getDuration());mSeekBar.setProgress(mp.getCurrentPosition());}@Overridepublic void onCompletion(MediaPlayer mp) {}@Overridepublic boolean onError(MediaPlayer mp, int what, int extra) {return false;}@Overridepublic 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);}}@Overridepublic void onSeekComplete(MediaPlayer mp) {//TODO}@Overridepublic void onVideoSizeChanged(MediaPlayer mp, int width, int height) {}@Overridepublic 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@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean b) {if(mPlayer != null && b){mPlayer.seekTo(progress);}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic 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"><SurfaceViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/controll_surfaceView"/>
</LinearLayout>

程序代码如下:

public class MediaControllerTestActivity extends Activity implementsMediaController.MediaPlayerControl,MediaPlayer.OnBufferingUpdateListener,SurfaceHolder.Callback{private MediaPlayer mediaPlayer;private MediaController controller;private int bufferPercentage = 0;@Overrideprotected 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);}@Overrideprotected 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();}}@Overrideprotected void onPause() {super.onPause();if (mediaPlayer.isPlaying()){mediaPlayer.stop();}}@Overrideprotected void onDestroy() {super.onDestroy();if (null != mediaPlayer){mediaPlayer.release();mediaPlayer = null;}}@Overridepublic boolean onTouchEvent(MotionEvent event) {controller.show();return super.onTouchEvent(event);}//MediaPlayer@Overridepublic void onPointerCaptureChanged(boolean hasCapture) {}//MediaPlayerControl@Overridepublic void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {bufferPercentage = i;}@Overridepublic void start() {if (null != mediaPlayer){mediaPlayer.start();}}@Overridepublic void pause() {if (null != mediaPlayer){mediaPlayer.pause();}}@Overridepublic int getDuration() {return mediaPlayer.getDuration();}@Overridepublic int getCurrentPosition() {return mediaPlayer.getCurrentPosition();}@Overridepublic void seekTo(int i) {mediaPlayer.seekTo(i);}@Overridepublic boolean isPlaying() {if (mediaPlayer.isPlaying()){return true;}return false;}@Overridepublic int getBufferPercentage() {return bufferPercentage;}@Overridepublic boolean canPause() {return true;}@Overridepublic boolean canSeekBackward() {return true;}@Overridepublic boolean canSeekForward() {return true;}@Overridepublic int getAudioSessionId() {return 0;}//SurfaceHolder.callback@Overridepublic void surfaceCreated(SurfaceHolder surfaceHolder) {mediaPlayer.setDisplay(surfaceHolder);mediaPlayer.prepareAsync();}@Overridepublic void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {}@Overridepublic void surfaceDestroyed(SurfaceHolder surfaceHolder) {}
}

效果图如下:

更多流媒体资讯,请关注小牛安卓干货铺,将进行不定期推送。

Android实现视频播放的3种实现方式相关推荐

  1. android视频播放的方法,Android实现视频播放的几种方式

    Android实现视频播放的3种方式 Android提供了常见的视频编码,解码机制,使用Android自带的MediaPlayer,MediaController等类可以很方便的实现视频播放的功能.支 ...

  2. Android 圆形头像的两种实现方式

    Android 圆形头像的两种实现方式 前言 这篇博客只是为了做一个记录而已,方便而后查询,核心代码都是直接采用鸿洋博客里面的代码的. 圆形头像在实际开发中实际很常见,一般来说,主要有两种实现方式: ...

  3. 浅谈Android文件管理器的几种实现方式(原理篇)--对我有帮助

    转自 https://blog.csdn.net/weixin_33698823/article/details/87269955 浅谈Android文件管理器的几种实现方式 为了完成毕业设计,我花费 ...

  4. android旋转动画的两种实现方式

    在android开发,我们会常常使用到旋转动画,普通情况下旋转动画有两种实现方式,一种是直接通过java代码去实现,第二种是通过配置文件实现动画.以下是两种动画的基本是用法: 纯Java代码实现: / ...

  5. android中资源文件的两种访问方式,Android_Android学习笔记-保存文件(Saving Files),Android设备有两种文件存储区域 - phpStudy...

    Android学习笔记-保存文件(Saving Files) Android设备有两种文件存储区域: 内部存储和外部存储 ("internal" and "externa ...

  6. android中资源文件的两种访问方式,在android开发中进行数据存储与访问的多种方式介绍...

    在android开发中进行数据存储与访问的多种方式介绍 更新时间:2013年06月07日 16:24:23   作者: 很多时候我们的软件需要对处理后的数据进行存储或再次访问,Android为数据存储 ...

  7. Android的surface的三种工作方式

    注:文章内容是基于kitkat进行的粗线条分析,做为学习过程中的小结. Surface的三种使用方式 Native层的Surface工作方式有:仅在Proxy端.Proxy和Service端协同.仅在 ...

  8. Android中Video的三种播放方式的实现

     在Android中,我们有三种方式来实现视频的播放. 1.使用其自带的播放器.指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型. 2.使用VideoView来 ...

  9. android 之Activity的五种传值方式 (在从当前Activity跳转到目标Activity时的传值方式)

    A.使用intent(意图)传值 MainActivity(源文件):         1.intent.putExtra(key,value):key一般是String,值为 java八大基本数据类 ...

最新文章

  1. Python学习系列(六)(模块)
  2. Vuejs自定义全局组件--loading
  3. 5.1 原型设计 - 页面流程图
  4. 生产环境的分布式任务调度框架如何选择?quartz、xxl-job、Elastic-Job、Saturn
  5. 面对 10 亿数据量的挑战,如何对系统进行性能优化?
  6. C++标准库之stack
  7. c++ 14 新特性
  8. ST电机库5.4.5FUL版本(ST MC SDK)
  9. 基础篇——树莓派通用引脚定义
  10. 全国省市县区乡镇级别的矢量文件(百度网盘可下载)
  11. supersu二进制更新安装失败_supersu二进制更新失败怎么办 supersu二进制更新失败解决方法...
  12. 苹果手机测距离_重量仅6g,智能距离检测,安卓苹果平板手机都能用,声光多级提醒...
  13. 计算机无法开机如何读u盘启动,电脑无法识别U盘启动盘怎么办?
  14. C语言中的strcat()函数
  15. 验证tensorflow是否安装成功
  16. 秋冬饮品研发没思路?带你看新品5大趋势!
  17. 瑞芯微 | 摄像头ov13850移植笔记
  18. Schema_CN28_XNN0付款/扣除和转账净额
  19. Mysql关键字之Union all说明
  20. 商品交易系统之---产品介绍

热门文章

  1. 【Unity】基础游戏单位GameObject中常用的属性和API
  2. 铝巨人铝模软件_助力建筑工业化发展PKPM-LMB铝模设计软件正式发布
  3. matlab由离散点绘制光滑曲线并额外标注点
  4. 阿里G2插件——柱状统计图,长变量值显示设置
  5. 成为腾讯开发者——如何使用QQ开放平台和微信开放平台
  6. android个人开发者广告平台
  7. Linux的简单命令 who echo cal clear date
  8. SK-learn实现k近邻算法【准确率随k值的变化】-------莺尾花种类预测
  9. 一些《集成电路与光刻机》笔记
  10. [语录]足球解说员贺炜语录