当前位置:   article > 正文

Android实现视频播放的3种实现方式(原生方式)_android 视频播放

android 视频播放

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

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

1、MediaController+VideoView实现方式

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

布局文件如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".VideoViewTestActivity">
  8. <VideoView
  9. android:id="@+id/videoView"
  10. android:layout_width="match_parent"
  11. android:layout_height="match_parent" />
  12. </android.support.constraint.ConstraintLayout>

程序代码如下:

  1. public class VideoViewTestActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_video_view_test);
  6. VideoView videoView = (VideoView)findViewById(R.id.videoView);
  7. //加载指定的视频文件
  8. String path = Environment.getExternalStorageDirectory().getPath()+"/20180730.mp4";
  9. videoView.setVideoPath(path);
  10. //创建MediaController对象
  11. MediaController mediaController = new MediaController(this);
  12. //VideoView与MediaController建立关联
  13. videoView.setMediaController(mediaController);
  14. //让VideoView获取焦点
  15. videoView.requestFocus();
  16. }
  17. }

使用此实现方式的步骤:

  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个回调函数如下:

  1. @Override
  2. public void surfaceCreated(SurfaceHolder holder) {
  3. }
  4. @Override
  5. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  6. }
  7. @Override
  8. public void surfaceDestroyed(SurfaceHolder holder) {
  9. }

布局文件如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".PlayVideoActivity">
  8. <RelativeLayout
  9. android:id="@+id/root_rl"
  10. android:layout_width="match_parent"
  11. android:layout_height="400dp"
  12. android:background="#000000">
  13. <SurfaceView
  14. android:id="@+id/surfaceView"
  15. android:layout_width="match_parent"
  16. android:layout_height="400dp" />
  17. <ImageView
  18. android:id="@+id/playOrPause"
  19. android:layout_width="60dp"
  20. android:layout_height="60dp"
  21. android:layout_centerInParent="true"
  22. android:src="@android:drawable/ic_media_play"/>
  23. <LinearLayout
  24. android:id="@+id/control_ll"
  25. android:layout_width="match_parent"
  26. android:layout_height="wrap_content"
  27. android:layout_alignParentBottom="true"
  28. android:background="#005500"
  29. android:orientation="vertical">
  30. <RelativeLayout
  31. android:layout_width="match_parent"
  32. android:layout_height="wrap_content"
  33. android:layout_marginLeft="10dp"
  34. android:layout_marginRight="10dp"
  35. android:orientation="horizontal"
  36. android:paddingBottom="5dp">
  37. <TextView
  38. android:id="@+id/tv_start_time"
  39. android:layout_width="wrap_content"
  40. android:layout_height="wrap_content"
  41. android:layout_alignParentLeft="true"
  42. android:layout_marginLeft="30dp"
  43. android:text="00.00"
  44. android:textColor="#ffffff"/>
  45. <TextView
  46. android:id="@+id/tv_separate_time"
  47. android:layout_width="wrap_content"
  48. android:layout_height="wrap_content"
  49. android:layout_toRightOf="@+id/tv_start_time"
  50. android:layout_marginLeft="1dp"
  51. android:text="/"
  52. android:textColor="#ffffff"/>
  53. <TextView
  54. android:id="@+id/tv_end_time"
  55. android:layout_width="wrap_content"
  56. android:layout_height="wrap_content"
  57. android:layout_toRightOf="@+id/tv_separate_time"
  58. android:layout_marginLeft="1dp"
  59. android:text="00.00"
  60. android:textColor="#ffffff"/>
  61. <ImageView
  62. android:id="@+id/tv_backward"
  63. android:layout_width="wrap_content"
  64. android:layout_height="wrap_content"
  65. android:layout_below="@+id/tv_start_time"
  66. android:layout_alignParentLeft="true"
  67. android:layout_marginLeft="1dp"
  68. android:src="@android:drawable/ic_media_rew"/>
  69. <SeekBar
  70. android:id="@+id/tv_progess"
  71. android:layout_width="match_parent"
  72. android:layout_height="wrap_content"
  73. android:layout_toRightOf="@+id/tv_backward"
  74. android:layout_toLeftOf="@+id/tv_forward"
  75. android:layout_below="@+id/tv_start_time"/>
  76. <ImageView
  77. android:id="@+id/tv_forward"
  78. android:layout_width="wrap_content"
  79. android:layout_height="wrap_content"
  80. android:layout_below="@+id/tv_start_time"
  81. android:layout_alignParentRight="true"
  82. android:layout_marginRight="1dp"
  83. android:src="@android:drawable/ic_media_ff"/>
  84. </RelativeLayout>
  85. </LinearLayout>
  86. </RelativeLayout>
  87. </android.support.constraint.ConstraintLayout>

程序代码如下:

  1. public class PlayVideoActivity extends AppCompatActivity implements SurfaceHolder.Callback,
  2. MediaPlayer.OnPreparedListener,
  3. MediaPlayer.OnCompletionListener,
  4. MediaPlayer.OnErrorListener,
  5. MediaPlayer.OnInfoListener, View.OnClickListener,
  6. MediaPlayer.OnSeekCompleteListener,
  7. MediaPlayer.OnVideoSizeChangedListener,
  8. SeekBar.OnSeekBarChangeListener,
  9. {
  10. private ImageView playOrPauseIv;
  11. private SurfaceView videoSuf;
  12. private MediaPlayer mPlayer;
  13. private SeekBar mSeekBar;
  14. private String path;
  15. private RelativeLayout rootViewRl;
  16. private LinearLayout controlLl;
  17. private TextView startTime, endTime;
  18. private ImageView forwardButton, backwardButton;
  19. private boolean isShow = false;
  20. public static final int UPDATE_TIME = 0x0001;
  21. public static final int HIDE_CONTROL = 0x0002;
  22. private Handler mHandler = new Handler() {
  23. @Override
  24. public void handleMessage(Message msg) {
  25. switch (msg.what) {
  26. case UPDATE_TIME:
  27. updateTime();
  28. mHandler.sendEmptyMessageDelayed(UPDATE_TIME, 500);
  29. break;
  30. case HIDE_CONTROL:
  31. hideControl();
  32. break;
  33. }
  34. }
  35. };
  36. @Override
  37. protected void onCreate(Bundle savedInstanceState) {
  38. super.onCreate(savedInstanceState);
  39. setContentView(R.layout.activity_play_video);
  40. initViews();
  41. initData();
  42. initSurfaceView();
  43. initPlayer();
  44. initEvent();
  45. }
  46. private void initData() {
  47. path = Environment.getExternalStorageDirectory().getPath() + "/20180730.mp4";//这里写上你的视频地址
  48. }
  49. private void initEvent() {
  50. playOrPauseIv.setOnClickListener(this);
  51. rootViewRl.setOnClickListener(this);
  52. rootViewRl.setOnTouchListener(this);
  53. forwardButton.setOnClickListener(this);
  54. backwardButton.setOnClickListener(this);
  55. mSeekBar.setOnSeekBarChangeListener(this);
  56. }
  57. private void initSurfaceView() {
  58. videoSuf = (SurfaceView) findViewById(R.id.surfaceView);
  59. videoSuf.setZOrderOnTop(false);
  60. videoSuf.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  61. videoSuf.getHolder().addCallback(this);
  62. }
  63. private void initPlayer() {
  64. mPlayer = new MediaPlayer();
  65. mPlayer.setOnCompletionListener(this);
  66. mPlayer.setOnErrorListener(this);
  67. mPlayer.setOnInfoListener(this);
  68. mPlayer.setOnPreparedListener(this);
  69. mPlayer.setOnSeekCompleteListener(this);
  70. mPlayer.setOnVideoSizeChangedListener(this);
  71. try {
  72. //使用手机本地视频
  73. mPlayer.setDataSource(path);
  74. } catch (Exception e) {
  75. e.printStackTrace();
  76. }
  77. }
  78. private void initViews() {
  79. playOrPauseIv = (ImageView) findViewById(R.id.playOrPause);
  80. startTime = (TextView) findViewById(R.id.tv_start_time);
  81. endTime = (TextView) findViewById(R.id.tv_end_time);
  82. mSeekBar = (SeekBar) findViewById(R.id.tv_progess);
  83. rootViewRl = (RelativeLayout) findViewById(R.id.root_rl);
  84. controlLl = (LinearLayout) findViewById(R.id.control_ll);
  85. forwardButton = (ImageView) findViewById(R.id.tv_forward);
  86. backwardButton = (ImageView) findViewById(R.id.tv_backward);
  87. }
  88. @Override
  89. public void surfaceCreated(SurfaceHolder holder) {
  90. mPlayer.setDisplay(holder);
  91. mPlayer.prepareAsync();
  92. }
  93. @Override
  94. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  95. }
  96. @Override
  97. public void surfaceDestroyed(SurfaceHolder holder) {
  98. }
  99. @Override
  100. public void onPrepared(MediaPlayer mp) {
  101. startTime.setText(FormatTimeUtil.formatLongToTimeStr(mp.getCurrentPosition()));
  102. endTime.setText(FormatTimeUtil.formatLongToTimeStr(mp.getDuration()));
  103. mSeekBar.setMax(mp.getDuration());
  104. mSeekBar.setProgress(mp.getCurrentPosition());
  105. }
  106. @Override
  107. public void onCompletion(MediaPlayer mp) {
  108. }
  109. @Override
  110. public boolean onError(MediaPlayer mp, int what, int extra) {
  111. return false;
  112. }
  113. @Override
  114. public boolean onInfo(MediaPlayer mp, int what, int extra) {
  115. return false;
  116. }
  117. private void play() {
  118. if (mPlayer == null) {
  119. return;
  120. }
  121. Log.i("playPath", path);
  122. if (mPlayer.isPlaying()) {
  123. mPlayer.pause();
  124. mHandler.removeMessages(UPDATE_TIME);
  125. mHandler.removeMessages(HIDE_CONTROL);
  126. playOrPauseIv.setVisibility(View.VISIBLE);
  127. playOrPauseIv.setImageResource(android.R.drawable.ic_media_play);
  128. } else {
  129. mPlayer.start();
  130. mHandler.sendEmptyMessageDelayed(UPDATE_TIME, 500);
  131. mHandler.sendEmptyMessageDelayed(HIDE_CONTROL, 5000);
  132. playOrPauseIv.setVisibility(View.INVISIBLE);
  133. playOrPauseIv.setImageResource(android.R.drawable.ic_media_pause);
  134. }
  135. }
  136. @Override
  137. public void onSeekComplete(MediaPlayer mp) {
  138. //TODO
  139. }
  140. @Override
  141. public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
  142. }
  143. @Override
  144. public void onClick(View v) {
  145. switch (v.getId()) {
  146. case R.id.tv_backward:
  147. backWard();
  148. break;
  149. case R.id.tv_forward:
  150. forWard();
  151. break;
  152. case R.id.playOrPause:
  153. play();
  154. break;
  155. case R.id.root_rl:
  156. showControl();
  157. break;
  158. }
  159. }
  160. /**
  161. * 更新播放时间
  162. */
  163. private void updateTime() {
  164. startTime.setText(FormatTimeUtil.formatLongToTimeStr(
  165. mPlayer.getCurrentPosition()));
  166. mSeekBar.setProgress(mPlayer.getCurrentPosition());
  167. }
  168. /**
  169. * 隐藏进度条
  170. */
  171. private void hideControl() {
  172. isShow = false;
  173. mHandler.removeMessages(UPDATE_TIME);
  174. controlLl.animate().setDuration(300).translationY(controlLl.getHeight());
  175. }
  176. /**
  177. * 显示进度条
  178. */
  179. private void showControl() {
  180. if (isShow) {
  181. play();
  182. }
  183. isShow = true;
  184. mHandler.removeMessages(HIDE_CONTROL);
  185. mHandler.sendEmptyMessage(UPDATE_TIME);
  186. mHandler.sendEmptyMessageDelayed(HIDE_CONTROL, 5000);
  187. controlLl.animate().setDuration(300).translationY(0);
  188. }
  189. /**
  190. * 设置快进10秒方法
  191. */
  192. private void forWard(){
  193. if(mPlayer != null){
  194. int position = mPlayer.getCurrentPosition();
  195. mPlayer.seekTo(position + 10000);
  196. }
  197. }
  198. /**
  199. * 设置快退10秒的方法
  200. */
  201. public void backWard(){
  202. if(mPlayer != null){
  203. int position = mPlayer.getCurrentPosition();
  204. if(position > 10000){
  205. position-=10000;
  206. }else{
  207. position = 0;
  208. }
  209. mPlayer.seekTo(position);
  210. }
  211. }
  212. //OnSeekBarChangeListener
  213. @Override
  214. public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
  215. if(mPlayer != null && b){
  216. mPlayer.seekTo(progress);
  217. }
  218. }
  219. @Override
  220. public void onStartTrackingTouch(SeekBar seekBar) {
  221. }
  222. @Override
  223. public void onStopTrackingTouch(SeekBar seekBar) {
  224. }
  225. }

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

实现效果如下所示:

3、MediaPlayer+SurfaceView+MediaController

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

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

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. tools:context=".MediaControllerTestActivity"
  7. android:id="@+id/root_ll">
  8. <SurfaceView
  9. android:layout_width="match_parent"
  10. android:layout_height="match_parent"
  11. android:id="@+id/controll_surfaceView"/>
  12. </LinearLayout>

程序代码如下:

  1. public class MediaControllerTestActivity extends Activity implements
  2. MediaController.MediaPlayerControl,
  3. MediaPlayer.OnBufferingUpdateListener,
  4. SurfaceHolder.Callback{
  5. private MediaPlayer mediaPlayer;
  6. private MediaController controller;
  7. private int bufferPercentage = 0;
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_media_controller_test);
  12. mediaPlayer = new MediaPlayer();
  13. controller = new MediaController(this);
  14. controller.setAnchorView(findViewById(R.id.root_ll));
  15. initSurfaceView();
  16. }
  17. private void initSurfaceView() {
  18. SurfaceView videoSuf = (SurfaceView) findViewById(R.id.controll_surfaceView);
  19. videoSuf.setZOrderOnTop(false);
  20. videoSuf.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  21. videoSuf.getHolder().addCallback(this);
  22. }
  23. @Override
  24. protected void onResume() {
  25. super.onResume();
  26. try {
  27. String path = Environment.getExternalStorageDirectory().getPath() + "/20180730.mp4";
  28. mediaPlayer.setDataSource(path);
  29. mediaPlayer.setOnBufferingUpdateListener(this);
  30. //mediaPlayer.prepare();
  31. controller.setMediaPlayer(this);
  32. controller.setEnabled(true);
  33. }catch (IOException e){
  34. e.printStackTrace();
  35. }
  36. }
  37. @Override
  38. protected void onPause() {
  39. super.onPause();
  40. if (mediaPlayer.isPlaying()){
  41. mediaPlayer.stop();
  42. }
  43. }
  44. @Override
  45. protected void onDestroy() {
  46. super.onDestroy();
  47. if (null != mediaPlayer){
  48. mediaPlayer.release();
  49. mediaPlayer = null;
  50. }
  51. }
  52. @Override
  53. public boolean onTouchEvent(MotionEvent event) {
  54. controller.show();
  55. return super.onTouchEvent(event);
  56. }
  57. //MediaPlayer
  58. @Override
  59. public void onPointerCaptureChanged(boolean hasCapture) {
  60. }
  61. //MediaPlayerControl
  62. @Override
  63. public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {
  64. bufferPercentage = i;
  65. }
  66. @Override
  67. public void start() {
  68. if (null != mediaPlayer){
  69. mediaPlayer.start();
  70. }
  71. }
  72. @Override
  73. public void pause() {
  74. if (null != mediaPlayer){
  75. mediaPlayer.pause();
  76. }
  77. }
  78. @Override
  79. public int getDuration() {
  80. return mediaPlayer.getDuration();
  81. }
  82. @Override
  83. public int getCurrentPosition() {
  84. return mediaPlayer.getCurrentPosition();
  85. }
  86. @Override
  87. public void seekTo(int i) {
  88. mediaPlayer.seekTo(i);
  89. }
  90. @Override
  91. public boolean isPlaying() {
  92. if (mediaPlayer.isPlaying()){
  93. return true;
  94. }
  95. return false;
  96. }
  97. @Override
  98. public int getBufferPercentage() {
  99. return bufferPercentage;
  100. }
  101. @Override
  102. public boolean canPause() {
  103. return true;
  104. }
  105. @Override
  106. public boolean canSeekBackward() {
  107. return true;
  108. }
  109. @Override
  110. public boolean canSeekForward() {
  111. return true;
  112. }
  113. @Override
  114. public int getAudioSessionId() {
  115. return 0;
  116. }
  117. //SurfaceHolder.callback
  118. @Override
  119. public void surfaceCreated(SurfaceHolder surfaceHolder) {
  120. mediaPlayer.setDisplay(surfaceHolder);
  121. mediaPlayer.prepareAsync();
  122. }
  123. @Override
  124. public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
  125. }
  126. @Override
  127. public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
  128. }
  129. }

效果图如下:

四、还可以使用ijk或者Vitamio

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/852482
推荐阅读
相关标签
  

闽ICP备14008679号