好几天没写博客了,处理了一点个人私事加上平时加班,基本上时间不充裕,上篇文章讲了一下用Mediaplayer来播放音乐,这次就讲讲使用Mediaplayer来和SurfaceView配合播放一个视频流媒体。MediaPlayer不仅可以播放视频,还可以与SurfaceView的配合,SurfaceView主要用于显示MediaPlayer播放的视频流媒体的画面渲染,两者可以一起协同播放视频。

基础维护

先来看下要实现的界面:

如果你看过上篇文章,就发现其实很简单的就是多了一个进度条,还有一个就是SurfaceView,就是下面那块黑色区域;

布局文件代码:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical"
  6. tools:context="com.example.googlevideo.MainActivity" >
  7.  
  8. <EditText
  9. android:id="@+id/edit_musicPath"
  10. android:layout_width="match_parent"
  11. android:layout_height="wrap_content"
  12. android:hint="输入MV的路径" />
  13.  
  14. <SeekBar
  15. android:id="@+id/seekBar_video"
  16. android:layout_width="match_parent"
  17. android:layout_height="wrap_content" />
  18.  
  19. <LinearLayout
  20. android:layout_width="match_parent"
  21. android:layout_height="wrap_content"
  22. android:orientation="horizontal" >
  23.  
  24. <Button
  25. android:id="@+id/btn_Play"
  26. android:layout_width="wrap_content"
  27. android:layout_height="wrap_content"
  28. android:onClick="playEvent"
  29. android:text="播放" />
  30.  
  31. <Button
  32. android:id="@+id/btn_Pause"
  33. android:layout_width="wrap_content"
  34. android:layout_height="wrap_content"
  35. android:onClick="pauseEvent"
  36. android:text="暂停" />
  37.  
  38. <Button
  39. android:id="@+id/btn_Stop"
  40. android:layout_width="wrap_content"
  41. android:layout_height="wrap_content"
  42. android:onClick="stopEvent"
  43. android:text="停止" />
  44.  
  45. <Button
  46. android:id="@+id/btn_Replay"
  47. android:layout_width="wrap_content"
  48. android:layout_height="wrap_content"
  49. android:onClick="replayEvent"
  50. android:text="重播" />
  51. </LinearLayout>
  52.  
  53. <SurfaceView
  54. android:id="@+id/surface_video"
  55. android:layout_width="match_parent"
  56. android:layout_height="match_parent" />
  57.  
  58. </LinearLayout>

 Demo实现

实现Demo之前应该讲讲视频播放的原理,先确定视频的格式,这个和解码相关,不同的格式视频编码不同,然后通过编码格式进行解码,最后得到一帧一帧的图像,并把这些图像快速的显示在界面上,即为播放一段视频。SurfaceView在Android中就是完成这个功能的。SurfaceView是配合MediaPlayer使用的,MediaPlayer也提供了相应的方法设置SurfaceView显示图片,只需要为MediaPlayer指定SurfaceView显示图像即可。它的完整签名:void setDisplay(SurfaceHolder sh)。它需要传递一个SurfaceHolder对象,SurfaceHolder可以理解为SurfaceView装载需要显示的一帧帧图像的容器,它可以通过SurfaceHolder.getHolder()方法获得。使用MediaPlayer配合SurfaceView播放视频的步骤与播放使用MediaPlayer播放MP3大体一致,只需要额外设置显示的SurfaceView即可。

先准备一段能播放的视频:

播放视频效果图:

代码如下:

  1. editText = (EditText) findViewById(R.id.edit_musicPath);
  2. pathString = editText.getText().toString().trim();
  3. File file = new File(pathString);
  4. if (file.exists()) {
  5. try {
  6. mediaPlayer = new MediaPlayer();
  7. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  8. mediaPlayer.setDataSource(pathString);
  9. //通过SurfaceView获取的Holder
  10. mediaPlayer.setDisplay(holder);
  11. mediaPlayer.prepare();
  12. mediaPlayer.start();
  13. btn_PlayButton.setEnabled(false);
  14. //设置Bar的最大值
  15. int max=mediaPlayer.getDuration();
  16. seekBarVideo.setMax(max);
  17. //定时器更新进度条
  18. timer=new Timer();
  19. timeTask=new TimerTask() {
  20.  
  21. @Override
  22. public void run() {
  23. // TODO Auto-generated method stub
  24. seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
  25. }
  26. };
  27. timer.schedule(timeTask, 0, 500);
  28. //视频播放完之后重新设置显示
  29. mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
  30.  
  31. @Override
  32. public void onCompletion(MediaPlayer mp) {
  33. // TODO Auto-generated method stub
  34. btn_PlayButton.setEnabled(true);
  35. }
  36. });
  37.  
  38. } catch (IOException e) {
  39. // TODO Auto-generated catch block
  40. e.printStackTrace();
  41. }
  42. } else {
  43. Toast.makeText(this, "Sorry,你输入的路径有问题,请仔细检查", Toast.LENGTH_SHORT)
  44. .show();
  45. }

SeekBar的使用: 

  1. //设置Bar的最大值
  2. int max=mediaPlayer.getDuration();
  3. seekBarVideo.setMax(max);
  4. //定时器更新进度条
  5. timer=new Timer();
  6. timeTask=new TimerTask() {
  7.  
  8. @Override
  9. public void run() {
  10. // TODO Auto-generated method stub
  11. seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
  12. }
  13. };
  14. timer.schedule(timeTask, 0, 500);

 其中holder是SurfaceHolder,在onCreate中获取:

  1. surfaceView = (SurfaceView) findViewById(R.id.surface_video);
  2. holder = surfaceView.getHolder();
  3. //兼容4.0以后的手机版本,本身是不维护的
  4. holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

 如果正在播放视频,最小化的时候是会有声音的,需要在回调函数中处理一下:

  1. holder.addCallback(new Callback() {
  2.  
  3. @Override
  4. public void surfaceDestroyed(SurfaceHolder holder) {
  5. // TODO Auto-generated method stub
  6. Log.i(tag, "销毁了Holder");
  7. if (mediaPlayer!=null&&mediaPlayer.isPlaying()) {
  8. currentPosition=mediaPlayer.getCurrentPosition();
  9. mediaPlayer.stop();
  10. mediaPlayer.release();
  11. mediaPlayer=null;
  12. timer.cancel();
  13. timeTask.cancel();
  14. timer=null;
  15. timeTask=null;
  16. }
  17. }
  18.  
  19. @Override
  20. public void surfaceCreated(SurfaceHolder holder) {
  21. // TODO Auto-generated method stub
  22. Log.i(tag,"创建了Holder");
  23. if (currentPosition>0) {
  24. try {
  25. mediaPlayer = new MediaPlayer();
  26. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  27. mediaPlayer.setDataSource(pathString);
  28. //通过SurfaceView获取的Holder
  29. mediaPlayer.setDisplay(holder);
  30. mediaPlayer.prepare();
  31. mediaPlayer.start();
  32. mediaPlayer.seekTo(currentPosition);
  33. btn_PlayButton.setEnabled(false);
  34. //视频播放完之后重新设置显示
  35. mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
  36.  
  37. @Override
  38. public void onCompletion(MediaPlayer mp) {
  39. // TODO Auto-generated method stub
  40. btn_PlayButton.setEnabled(true);
  41. }
  42. });
  43.  
  44. int max=mediaPlayer.getDuration();
  45. seekBarVideo.setMax(max);
  46. //定时器更新进度条
  47. timer=new Timer();
  48. timeTask=new TimerTask() {
  49.  
  50. @Override
  51. public void run() {
  52. // TODO Auto-generated method stub
  53. seekBarVideo.setProgress(mediaPlayer.getCurrentPosition());
  54. }
  55. };
  56. timer.schedule(timeTask, 0, 500);
  57. } catch (Exception e) {
  58. // TODO: handle exception
  59. }
  60. }
  61. }
  62.  
  63. @Override
  64. public void surfaceChanged(SurfaceHolder holder, int format, int width,
  65. int height) {
  66. // TODO Auto-generated method stub
  67. Log.i(tag,"改变了Holder");
  68. }
  69. });

  进度条是SeekBar,如果需要快进或者后退的时候是需要将焦点赋值给mediaPlayer的:

  1. seekBarVideo=(SeekBar) findViewById(R.id.seekBar_video);
  2. seekBarVideo.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
  3.  
  4. @Override
  5. public void onStopTrackingTouch(SeekBar seekBar) {
  6. // TODO Auto-generated method stub
  7. int position=seekBar.getProgress();
  8. if (mediaPlayer!=null&&mediaPlayer.isPlaying()) {
  9. mediaPlayer.seekTo(position);
  10. }
  11. }
  12.  
  13. @Override
  14. public void onStartTrackingTouch(SeekBar seekBar) {
  15. // TODO Auto-generated method stub
  16.  
  17. }
  18.  
  19. @Override
  20. public void onProgressChanged(SeekBar seekBar, int progress,
  21. boolean fromUser) {
  22. // TODO Auto-generated method stub
  23.  
  24. }
  25. });

  暂停事件:

  1. public void pauseEvent(View view) {
  2. if (btn_PauseButton.getText().equals("继续")) {
  3. mediaPlayer.start();
  4. btn_PauseButton.setText("暂停");
  5. return;
  6. }
  7. if (mediaPlayer != null && mediaPlayer.isPlaying()) {
  8. mediaPlayer.pause();
  9. btn_PauseButton.setText("继续");
  10. }
  11. }

 停止事件:

  1. public void stopEvent(View view) {
  2. if (mediaPlayer != null && mediaPlayer.isPlaying()) {
  3. btn_PlayButton.setEnabled(true);
  4. mediaPlayer.stop();
  5. // 释放mediaplayer否则的话会占用内存
  6. mediaPlayer.release();
  7. mediaPlayer = null;
  8. }
  9. btn_PauseButton.setText("暂停");
  10. btn_PlayButton.setEnabled(true);
  11. }

  重播事件:

  1. public void replayEvent(View view) {
  2. surfaceView.setVisibility(View.VISIBLE);
  3. if (mediaPlayer != null && mediaPlayer.isPlaying()) {
  4. mediaPlayer.seekTo(0);
  5. } else {
  6. playEvent(view);
  7. }
  8. // 重播的时候应该设置播放的状态
  9. btn_PlayButton.setEnabled(true);
  10. }

Android视频播放-SurfaceView和Mediaplayer的更多相关文章

  1. Android音视频之MediaPlayer音视频播放

    前言: 昨天总结了视频录制,今天来学习一下视频的播放,Android的视频播放主要采用MediaPlayer类. MediaPlayer介绍 MediaPlayer类可用于控制音频/视频文件或流的播放 ...

  2. 【Android 多媒体开发】 MediaPlayer 网络视频播放器

    作者 : 万境绝尘 (octopus_truth@163.com) 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/3889514 ...

  3. Android 视频播放器 (二):使用MediaPlayer播放视频

    在 Android 视频播放器 (一):使用VideoView播放视频 我们讲了一下如何使用VideoView播放视频,了解了基本的播放器的一些知识和内容.也知道VideoView内部封装的就是Med ...

  4. android中使用surfaceview+MediaPlayer播放视频

    Android中播放视频主要有两种方式: 使用其自带的播放器.指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型 使用android自带的VideoView,这种方法 ...

  5. android视频播放心得体会

    android视频播放主要是两种方式1.系统封装好的videoplayer,有前进.后退.暂停/播放.拉动最基本的功能,够一般使用,操作办法也很简单,如果需要自定义程度高就需要用到第二种方法:Surf ...

  6. android视频播放

    视频播放我们用到的是MediaPlayer,显示控件使用的surfaceView 我们向SD卡中先添加个视频文件,我的是xajh.3gp,不要用mp4,MP4会出现 should have subti ...

  7. Android有关surfaceView又一次创建的问题。

    近期在做一个Android视频播放器的项目.遇到一个问题,就是锁屏之后.surfaceview就会被销毁掉,然后就会出现各种错误.到csdn论坛去发帖提问,各种所谓的大神都说,解锁屏在又一次创建一个, ...

  8. Android 视频播放器 (四):使用ExoPlayer播放视频

    一.简介 ExoPlayer是一个Android应用层的媒体播放器,它提供了一套可替换Android MediaPlayer的API,可以播放本地或者是线上的音视频资源.ExoPlayer支持一些An ...

  9. Android 视频播放器切换到下个视频时残留上个视频画面的解决办法

    最近在做一个Android视频播放器,遇到一个问题:切换到下一个视频时,中间会停留上一个视频的残存画面.   这是怎么回事?   我在网上找了很多资料,终于找到了原因:我是用自定义一个surfacev ...

随机推荐

  1. synchoronized和lock区别

    synchoronized是JVM的内置锁,而lock是Java代码实现的.lock是sync对的扩展,完全可以替代后者.lock可以重入,允许同一个线程连续多次获得同一把锁.其次,lock独有的功能 ...

  2. Linux安装系统选择 日报 18/06/23

    Linux安装系统选择 Centos7 程序体积7个G,如果是学习伊始, 注意不要选择那个体积小的,因为我装过之后进去发现这个wifie还要自己进行一些烈的命令才能连接成功.很麻烦的. 安装比较顺利但 ...

  3. sklearn六大板块

    六大板块 分类 回归 聚类 数据降维 数据预处理 特征抽取 统一API estimator.fit(X_train,[y_train]) estimator.fit(X_train,[y_train] ...

  4. navicat premium 的使用——navicat 连接MySQL数据库

    最近,在学习navicat premium这款第三方软件,他是一个三方数据库管理软件,在前一段时间实习的时候,我使用这款软件调用过服务器上的数据库,不过,当时并没有仔细研究,再次遇到这个软件,我决定仔 ...

  5. CF17E Palisection 差分+manacher算法

    题目大意: 给定一个串$S$,询问有多少对相交的回文子串 直接做的办法: 我们先考虑求出以$i$为结尾的串的数量,这个很好统计 之后,我们再求出所有包含了点$i$的回文串的数目 这个相当于在$i$的左 ...

  6. 2-SAT的一些题目

    http://blog.sina.com.cn/s/blog_64675f540100k2xj.html 都一个类型的不是很想写.

  7. 2018 计蒜之道复赛 贝壳找房魔法师顾问(并查集+dfs判环)

    贝壳找房在遥远的传奇境外,找到了一个强大的魔法师顾问.他有 22 串数量相同的法力水晶,每个法力水晶可能有不同的颜色.为了方便起见,可以将每串法力水晶视为一个长度不大于 10^5105,字符集不大于  ...

  8. voith项目配置服务程序

    项目需求: 1.程序可以最小化到任务栏 2.tpms标签和限速标签同时只能选择一个,并且要通过button确定修改 3.在程序中需要显示SequenceScanner1.0服务的运行状态 4.能够打开 ...

  9. UC浏览器 垂直水平居中

    今天使用下述方式定义水平垂直居中不起作用 #box{ position: fixed; left:; right:; top:; bottom:; margin: auto; } 然后改用: #box ...

  10. Windows下C语言调用dll动态链接库

    dll是windows下的动态链接库文件,下面记录一下在windows下如何调用C语言开发的dll动态链接库. 1.dll动态链接库的源代码 hello_dll.c #include "st ...