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) {}
}
FormatTimeUtil代码:
/*** 取消科学计数法,原样输出double数值* */
public class FormatTimeUtil {public FormatTimeUtil(){}/*** Formats the time to look like "HH:MM:SS"** @param millis The number of elapsed milliseconds* @return A formatted time value*/public static String formatLongToTimeStr(final long millis) {//TODO does not support hour>=100 (4.1 days)return String.format("%02d:%02d:%02d",millis / (1000 * 60 * 60),(millis / (1000 * 60)) % 60,(millis / 1000) % 60);}}

注意事项: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 播放视频的三种方式相关推荐

  1. Android录制音频的三种方式

    对于录制音频,Android系统就都自带了一个小小的应用,可是使用起来可能不是特别的灵活.所以有提供了另外的俩种. 下边来介绍下这三种录制的方式; 1.通过Intent调用系统的录音器功能,然后在录制 ...

  2. Android 音频录制 的三种方式

    对于录制音频,Android系统就都自带了一个小小的应用,可是使用起来可能不是特别的灵活.所以有提供了另外的俩种. 下边来介绍下这三种录制的方式; 1.通过Intent调用系统的录音器功能,然后在录制 ...

  3. Android 使用OpenCV的三种方式(Android Studio)

    from: http://blog.csdn.net/sbsujjbcy/article/details/49520791 其实最早接触OpenCV是很久很久之前的事了,大概在2013年的5,6月份, ...

  4. android xml解析的三种方式

    2019独角兽企业重金招聘Python工程师标准>>> 在android开发中,经常用到去解析xml文件,常见的解析xml的方式有一下三种:SAX.Pull.Dom解析方式.最近做了 ...

  5. Android解析XML的三种方式

    在Android中提供了三种解析XML的方式:DOM(Document Objrect Model),SAX(Simple API XML),以及Android推荐的Pull解析方式. 如图: 本篇博 ...

  6. 【安卓】Android播放器的三种实现方法

    转载自:http://blog.csdn.net/wozuihaole/article/details/60867076 今天来说一下Android中怎么实现视频播放,我主要说三种: 1.MediaP ...

  7. Android播放器的三种实现方法

    转载自:http://blog.csdn.net/wozuihaole/article/details/60867076 今天来说一下Android中怎么实现视频播放,我主要说三种: 1.MediaP ...

  8. Unity3D教程:播放视频的两种方式

    Unity3D中播放游戏视频的方式有两种,第一种是在游戏对象中播放,就好比在游戏世界中创建一个Plane面对象,摄像机直直的照射在这个面上.第二种是在GUI层面上播放视频.播放视频其实和贴图非常相像, ...

  9. 【Unity 3D】常用播放视频的几种方式

    [准备工作] 在Unity3D中想要成功播放视频并不是一件太简单的事,还是有着诸多限制的. 要求如下: (1) 视频.格式支持 .mov, .mpg, .mpeg, .mp4, .avi, .asf ...

最新文章

  1. [C#]关于Access的“INSERT INTO 语句的语法错误”问题
  2. 【小项目关键技术六】控制北斗 GPS 定位 / UWB 室内定位
  3. relu不可微为什么可用于深度学习
  4. 机器学习笔记1(K-近邻算法)
  5. Eclipse 插件开发遇到问题心得总结
  6. 2019年南大计算机开放日_开放式硬件计算机年
  7. 130分的计算机专科学校排名及分数线,2021专科学校排名及分数线是多少
  8. 前端的ajax缓存,解析jquery中的ajax缓存问题
  9. RHCE实验环境虚拟机下载及注意事项
  10. yagmail群发邮件
  11. linux mysql数据库升级_Linux升级mysql到5.7
  12. Java的Socket编程实例
  13. .Net平台下安装DotNetBar
  14. Vue之echarts圆饼图详解
  15. java 打印 xps_使用Java 将PPT转换为PDF、XPS等格式
  16. 软件测试面试必考题:自我介绍
  17. Ansible9:变量之Fact
  18. 第九届蓝桥杯稍小分数c语言,【第九届蓝桥杯大赛征文】蓝桥梦
  19. 木瓜移动再度荣获2022“Google优秀合作伙伴”
  20. 从“Real如我”来看当前社交APP开发-深圳积木创意科技

热门文章

  1. Python 文件类型(*.py/*.pyc/*.pyo)
  2. 起点小说下载工具 代码汇
  3. 过孔解析 分类 特征 作用
  4. 走在全球化长征路上的BitZ
  5. vue 静态html 路由,vue路由教程之静态路由
  6. 女朋友让我写,我不知道该如何写?怎么办?
  7. linux第一次月考成绩分析
  8. R语言利用ggplot画图时调整坐标轴字体大小
  9. 嵌入式C语言设计模式 --- 原型模式
  10. 第四章:业界主流云产品介绍