Android提高第二十一篇之MediaPlayer播放网络视频

本文来自http://blog.csdn.net/hellogv/,引用必须注明出处!

上次讲解了MediaPlayer播放网络音频,介绍了MediaPlayer关于网络音频的缓冲和进度条控制的方法,这次再讲解MediaPlayer播放网络视频。播放网络视频比播放网络音频多需要一个SurfaceView而已,已经熟悉MediaPlayer播放网络音频之后,相信大家对播放网络视频也能很快地掌握。先来看看本文程序运行截图:

Android提高第二十一篇之MediaPlayer播放网络视频

本文程序的视频来自http://daily3gp.com,大家可以替换程序中的视频链接,试试其他影片。

main.xml的源码如下:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_height="fill_parent"android:layout_width="fill_parent">
  4. <SurfaceViewandroid:id="@+id/surfaceView1"
  5. android:layout_height="fill_parent"android:layout_width="fill_parent"></SurfaceView>
  6. <LinearLayoutandroid:layout_height="wrap_content"
  7. android:layout_width="fill_parent"android:layout_gravity="bottom"
  8. android:orientation="vertical">
  9. <LinearLayoutandroid:orientation="horizontal"
  10. android:layout_gravity="center_horizontal"android:layout_marginTop="4.0dip"
  11. android:layout_height="wrap_content"android:layout_width="wrap_content">
  12. <Buttonandroid:layout_width="wrap_content"
  13. android:layout_height="wrap_content"android:id="@+id/btnPlayUrl"
  14. android:text="播放网络视频"></Button>
  15. <Buttonandroid:layout_height="wrap_content"android:id="@+id/btnPause"
  16. android:text="暂停"android:layout_width="80dip"></Button>
  17. <Buttonandroid:layout_height="wrap_content"
  18. android:layout_width="80dip"android:text="停止"android:id="@+id/btnStop"></Button>
  19. </LinearLayout>
  20. <LinearLayoutandroid:orientation="horizontal"
  21. android:layout_width="fill_parent"android:layout_height="wrap_content"
  22. android:layout_marginBottom="20dip">
  23. <SeekBarandroid:paddingRight="10dip"android:layout_gravity="center_vertical"
  24. android:paddingLeft="10dip"android:layout_weight="1.0"
  25. android:layout_height="wrap_content"android:layout_width="wrap_content"
  26. android:id="@+id/skbProgress"android:max="100"></SeekBar>
  27. </LinearLayout>
  28. </LinearLayout>
  29. </FrameLayout>

Player.java是本文的核心,Player.java实现了“进度条更新”、“数据缓冲”、“SurfaceHolder生命周期”等功能,其中“SurfaceHolder生命周期”是视频与音频播放的最大区别,通过surfaceCreated()、surfaceDestroyed()、surfaceChanged()可以创建/释放某些资源。下面这个地方需要注意一下:

  1. videoWidth=mediaPlayer.getVideoWidth();
  2. videoHeight=mediaPlayer.getVideoHeight();
  3. if(videoHeight!=0&&videoWidth!=0){
  4. arg0.start();
  5. }

有些视频是android播放器不能播放的,不能播放时videoHeight=0,videoWidth=0,以此来判断是否播放视频。

Player.java源码如下:

  1. packagecom.videoplayer;
  2. importjava.io.IOException;
  3. importjava.util.Timer;
  4. importjava.util.TimerTask;
  5. importandroid.media.AudioManager;
  6. importandroid.media.MediaPlayer;
  7. importandroid.media.MediaPlayer.OnBufferingUpdateListener;
  8. importandroid.media.MediaPlayer.OnCompletionListener;
  9. importandroid.os.Handler;
  10. importandroid.os.Message;
  11. importandroid.util.Log;
  12. importandroid.view.SurfaceHolder;
  13. importandroid.view.SurfaceView;
  14. importandroid.widget.SeekBar;
  15. publicclassPlayerimplementsOnBufferingUpdateListener,
  16. OnCompletionListener,MediaPlayer.OnPreparedListener,
  17. SurfaceHolder.Callback{
  18. privateintvideoWidth;
  19. privateintvideoHeight;
  20. publicMediaPlayermediaPlayer;
  21. privateSurfaceHoldersurfaceHolder;
  22. privateSeekBarskbProgress;
  23. privateTimermTimer=newTimer();
  24. publicPlayer(SurfaceViewsurfaceView,SeekBarskbProgress)
  25. {
  26. this.skbProgress=skbProgress;
  27. surfaceHolder=surfaceView.getHolder();
  28. surfaceHolder.addCallback(this);
  29. surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  30. mTimer.schedule(mTimerTask,0,1000);
  31. }
  32. /*******************************************************
  33. *通过定时器和Handler来更新进度条
  34. ******************************************************/
  35. TimerTaskmTimerTask=newTimerTask(){
  36. @Override
  37. publicvoidrun(){
  38. if(mediaPlayer==null)
  39. return;
  40. if(mediaPlayer.isPlaying()&&skbProgress.isPressed()==false){
  41. handleProgress.sendEmptyMessage(0);
  42. }
  43. }
  44. };
  45. HandlerhandleProgress=newHandler(){
  46. publicvoidhandleMessage(Messagemsg){
  47. intposition=mediaPlayer.getCurrentPosition();
  48. intduration=mediaPlayer.getDuration();
  49. if(duration>0){
  50. longpos=skbProgress.getMax()*position/duration;
  51. skbProgress.setProgress((int)pos);
  52. }
  53. };
  54. };
  55. //*****************************************************
  56. publicvoidplay()
  57. {
  58. mediaPlayer.start();
  59. }
  60. publicvoidplayUrl(StringvideoUrl)
  61. {
  62. try{
  63. mediaPlayer.reset();
  64. mediaPlayer.setDataSource(videoUrl);
  65. mediaPlayer.prepare();//prepare之后自动播放
  66. //mediaPlayer.start();
  67. }catch(IllegalArgumentExceptione){
  68. //TODOAuto-generatedcatchblock
  69. e.printStackTrace();
  70. }catch(IllegalStateExceptione){
  71. //TODOAuto-generatedcatchblock
  72. e.printStackTrace();
  73. }catch(IOExceptione){
  74. //TODOAuto-generatedcatchblock
  75. e.printStackTrace();
  76. }
  77. }
  78. publicvoidpause()
  79. {
  80. mediaPlayer.pause();
  81. }
  82. publicvoidstop()
  83. {
  84. if(mediaPlayer!=null){
  85. mediaPlayer.stop();
  86. mediaPlayer.release();
  87. mediaPlayer=null;
  88. }
  89. }
  90. @Override
  91. publicvoidsurfaceChanged(SurfaceHolderarg0,intarg1,intarg2,intarg3){
  92. Log.e("mediaPlayer","surfacechanged");
  93. }
  94. @Override
  95. publicvoidsurfaceCreated(SurfaceHolderarg0){
  96. try{
  97. mediaPlayer=newMediaPlayer();
  98. mediaPlayer.setDisplay(surfaceHolder);
  99. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  100. mediaPlayer.setOnBufferingUpdateListener(this);
  101. mediaPlayer.setOnPreparedListener(this);
  102. }catch(Exceptione){
  103. Log.e("mediaPlayer","error",e);
  104. }
  105. Log.e("mediaPlayer","surfacecreated");
  106. }
  107. @Override
  108. publicvoidsurfaceDestroyed(SurfaceHolderarg0){
  109. Log.e("mediaPlayer","surfacedestroyed");
  110. }
  111. @Override
  112. /**
  113. *通过onPrepared播放
  114. */
  115. publicvoidonPrepared(MediaPlayerarg0){
  116. videoWidth=mediaPlayer.getVideoWidth();
  117. videoHeight=mediaPlayer.getVideoHeight();
  118. if(videoHeight!=0&&videoWidth!=0){
  119. arg0.start();
  120. }
  121. Log.e("mediaPlayer","onPrepared");
  122. }
  123. @Override
  124. publicvoidonCompletion(MediaPlayerarg0){
  125. //TODOAuto-generatedmethodstub
  126. }
  127. @Override
  128. publicvoidonBufferingUpdate(MediaPlayerarg0,intbufferingProgress){
  129. skbProgress.setSecondaryProgress(bufferingProgress);
  130. intcurrentProgress=skbProgress.getMax()*mediaPlayer.getCurrentPosition()/mediaPlayer.getDuration();
  131. Log.e(currentProgress+"%play",bufferingProgress+"%buffer");
  132. }
  133. }

test_videoplayer.java是主程序,负责调用Player类,其中关键部分是SeekBarChangeEvent这个SeekBar拖动的事件:SeekBar的Progress是0~SeekBar.getMax()之内的数,而MediaPlayer.seekTo()的参数是0~MediaPlayer.getDuration()之内数,所以MediaPlayer.seekTo()的参数是(progress/seekBar.getMax())*MediaPlayer.getDuration()。

test_videoplayer.java源码如下:

  1. packagecom.videoplayer;
  2. importandroid.app.Activity;
  3. importandroid.content.pm.ActivityInfo;
  4. importandroid.net.Uri;
  5. importandroid.os.Bundle;
  6. importandroid.util.Log;
  7. importandroid.view.SurfaceView;
  8. importandroid.view.View;
  9. importandroid.view.View.OnClickListener;
  10. importandroid.widget.Button;
  11. importandroid.widget.SeekBar;
  12. publicclasstest_videoplayerextendsActivity{
  13. privateSurfaceViewsurfaceView;
  14. privateButtonbtnPause,btnPlayUrl,btnStop;
  15. privateSeekBarskbProgress;
  16. privatePlayerplayer;
  17. /**Calledwhentheactivityisfirstcreated.*/
  18. @Override
  19. publicvoidonCreate(BundlesavedInstanceState){
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.main);
  22. setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  23. surfaceView=(SurfaceView)this.findViewById(R.id.surfaceView1);
  24. btnPlayUrl=(Button)this.findViewById(R.id.btnPlayUrl);
  25. btnPlayUrl.setOnClickListener(newClickEvent());
  26. btnPause=(Button)this.findViewById(R.id.btnPause);
  27. btnPause.setOnClickListener(newClickEvent());
  28. btnStop=(Button)this.findViewById(R.id.btnStop);
  29. btnStop.setOnClickListener(newClickEvent());
  30. skbProgress=(SeekBar)this.findViewById(R.id.skbProgress);
  31. skbProgress.setOnSeekBarChangeListener(newSeekBarChangeEvent());
  32. player=newPlayer(surfaceView,skbProgress);
  33. }
  34. classClickEventimplementsOnClickListener{
  35. @Override
  36. publicvoidonClick(Viewarg0){
  37. if(arg0==btnPause){
  38. player.pause();
  39. }elseif(arg0==btnPlayUrl){
  40. Stringurl="http://daily3gp.com/vids/family_guy_penis_car.3gp";
  41. player.playUrl(url);
  42. }elseif(arg0==btnStop){
  43. player.stop();
  44. }
  45. }
  46. }
  47. classSeekBarChangeEventimplementsSeekBar.OnSeekBarChangeListener{
  48. intprogress;
  49. @Override
  50. publicvoidonProgressChanged(SeekBarseekBar,intprogress,
  51. booleanfromUser){
  52. //原本是(progress/seekBar.getMax())*player.mediaPlayer.getDuration()
  53. this.progress=progress*player.mediaPlayer.getDuration()
  54. /seekBar.getMax();
  55. }
  56. @Override
  57. publicvoidonStartTrackingTouch(SeekBarseekBar){
  58. }
  59. @Override
  60. publicvoidonStopTrackingTouch(SeekBarseekBar){
  61. //seekTo()的参数是相对与影片时间的数字,而不是与seekBar.getMax()相对的数字
  62. player.mediaPlayer.seekTo(progress);
  63. }
  64. }
  65. }