10.2.2 网络视频播放

    Android支持采用第9章讨论的3种视频播放方法来播放HTTP和RTSP视频。无须改变原来的源代码,就可以通过意图触发内置的媒体播放器活动或者使用VideoView类来播放任何形式的网络视频。只需要将HTTP或RTSP URL作为视频Uri,那么只要是支持的格式,它就可以工作。

    1.VideoView网络视频播放器

    下面是来自第9章的ViewTheVideo活动示例,其使用一个VideoView及一个指向YouTube移动站点视频的RTSP URL。唯一的变化是构造videoUri所传入的字符串。

 1 package com.nthm.androidtestActivity;
 2 
 3 import com.nthm.androidtest.R;
 4 import android.app.Activity;
 5 import android.net.Uri;
 6 import android.os.Bundle;
 7 import android.widget.MediaController;
 8 import android.widget.VideoView;
 9 
10 public class ViewTheVideo extends Activity {
11     private VideoView vv;
12     @Override
13     protected void onCreate(Bundle savedInstanceState) {
14         super.onCreate(savedInstanceState);
15         setContentView(R.layout.viewthevideo);
16         vv=(VideoView) findViewById(R.id.VedioView);
17         vv.setMediaController(new MediaController(ViewTheVideo.this));
18         Uri videoUri=Uri.parse("");//此处的路径下的视频必须是能够渐进式累进式的视频
19         vv.setVideoURI(videoUri);
20         vv.start();
21     }
22 }

    2.MediaPlayer网络视频播放器

    将MediaPlayer用于网络视频播放类似于在第9章中讨论过的MediaPlayer和MediaController代码。在下面的示例中会突出显示专门与网络播放相关的部分。关于MediaPlayer和MediaController的完整解释,请参阅第9章中的示例。

 1 package com.nthm.androidtestActivity;
 2 
 3 import java.io.IOException;
 4 import com.nthm.androidtest.R;
 5 import android.app.Activity;
 6 import android.media.MediaPlayer;
 7 import android.media.MediaPlayer.OnBufferingUpdateListener;
 8 import android.media.MediaPlayer.OnCompletionListener;
 9 import android.media.MediaPlayer.OnErrorListener;
10 import android.media.MediaPlayer.OnInfoListener;
11 import android.media.MediaPlayer.OnPreparedListener;
12 import android.media.MediaPlayer.OnSeekCompleteListener;
13 import android.media.MediaPlayer.OnVideoSizeChangedListener;
14 import android.os.Bundle;
15 import android.view.Display;
16 import android.view.MotionEvent;
17 import android.view.SurfaceHolder;
18 import android.view.SurfaceHolder.Callback;
19 import android.view.SurfaceView;
20 import android.view.View;
21 import android.view.View.OnTouchListener;
22 import android.widget.LinearLayout;
23 import android.widget.MediaController;
24 import android.widget.MediaController.MediaPlayerControl;
25 import android.widget.TextView;

    StreamingVideoPlayer活动实现了许多可用的监听以及源自MediaPlayer、SurfaceHolderMediaController的回调抽象类。OnBufferingUpdateListener在处理网络传输的媒体时特别的有用。这个类指定了一个onBufferingUpdate方法,当缓冲媒体时重复调用该方法,从而能够跟踪缓冲区的填充程度。

 1 public class StreamingVideoPlayer extends Activity implements
 2         OnCompletionListener, OnErrorListener, OnInfoListener,
 3         OnBufferingUpdateListener, OnPreparedListener, OnSeekCompleteListener,
 4         OnVideoSizeChangedListener, Callback, MediaPlayerControl,OnTouchListener {
 5     private MediaController controller;
 6     private Display currentDisplay;
 7     private SurfaceView surfaceView;
 8     private SurfaceHolder surfaceHolder;
 9     private MediaPlayer mediaPlayer;
10     private View mainView;

    在当前版本中将使用一个称为statusView的TextView对象,以将状态消息显示给用户。之所以这么做,是因为通过Internet加载待播放的视频会花费相当长的时间,如果没有一些状态消息,那么用户可能会认为应用程序已经挂起。

 1     private TextView statusView;
 2     private int videoWidth=0;
 3     private int videoHeight=0;
 4     private boolean readyToPlay=false;
 5     @Override
 6     protected void onCreate(Bundle savedInstanceState) {
 7         super.onCreate(savedInstanceState);
 8         setContentView(R.layout.streamimgvideoplayer);
 9         mainView=findViewById(R.id.MainView);
10         statusView=(TextView) findViewById(R.id.StatusTextView);
11         
12         surfaceView=(SurfaceView) findViewById(R.id.SurfaceView);
13         surfaceHolder=surfaceView.getHolder();
14         surfaceHolder.addCallback(this);
15         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
16         
17         mediaPlayer=new MediaPlayer();
18         statusView.setText("MediaPlayer Created");
19         mediaPlayer.setOnCompletionListener(this);
20         mediaPlayer.setOnErrorListener(this);
21         mediaPlayer.setOnInfoListener(this);
22         mediaPlayer.setOnPreparedListener(this);
23         mediaPlayer.setOnSeekCompleteListener(this);
24         mediaPlayer.setOnVideoSizeChangedListener(this);

    在MediaPlayer事件监听器的列表中,活动实现并注册为OnBufferingUpdateListener。

1         mediaPlayer.setOnBufferingUpdateListener(this);

    与播放SD卡上的文件不同,现在将播放一个来自RTSP服务器的文件。在字符串filePath中指定该文件的URL。然后,使用MediaPlayer的setDataSource方法,并传入filePath字符串。由于MediaPlayer知道如何处理从一个RTSP服务器加载并播放数据,因此不必做其他的改动来处理它。

 1         String filePath="";//可用于渐进式加载的视频路径
 2         try {
 3             mediaPlayer.setDataSource(filePath);
 4         } catch (IllegalArgumentException e) {
 5             e.printStackTrace();
 6         } catch (SecurityException e) {
 7             e.printStackTrace();
 8         } catch (IllegalStateException e) {
 9             e.printStackTrace();
10         } catch (IOException e) {
11             e.printStackTrace();
12         }
13         statusView.setText("MediaPlayer setDataSource Set");
14         currentDisplay=getWindowManager().getDefaultDisplay();
15         controller=new MediaController(this);
16     }
17 
18 
19     @Override
20     public void surfaceCreated(SurfaceHolder holder) {
21        mediaPlayer.setDisplay(holder);
22        statusView.setText("MediaPlayer Display surface Set");

    我们将使用MediaPlayer的prepareAsync方法而不是prepare方法。prepareAsync方法在后台中一个单独的线程上做准备工作,从而使得用户界面不会被挂起。因此,这将允许用户执行其他操作,或者允许开发人员显示一个加载动画或类似的内容。

1        try{
2        mediaPlayer.prepareAsync();
3        }catch(Exception e){
4           finish(); 
5        }

    因此,通过更新由statusView显示的状态信息,用户将知道在运行prepareAsync时发生了什么。

 1        statusView.setText("MediaPlayer preparing");
 2     }
 3     @Override
 4     public void surfaceChanged(SurfaceHolder holder, int format, int width,
 5             int height) {
 6 
 7     }
 8     @Override
 9     public void surfaceDestroyed(SurfaceHolder holder) {
10 
11     }
12     @Override
13     public void onCompletion(MediaPlayer mp) {
14         statusView.setText("MediaPlayer Playback Completed");
15     }
16     @Override
17     public boolean onInfo(MediaPlayer mp, int what, int extra) {
18         return false;
19     }
20 
21     @Override
22     public boolean onError(MediaPlayer mp, int what, int extra) {
23         return false;
24     }
25     @Override
26     public void onPrepared(MediaPlayer mp) {
27         statusView.setText("MediaPlayer Prepared");
28          videoWidth=mp.getVideoWidth();
29          videoHeight=mp.getVideoHeight();
30          
31          if(videoWidth>currentDisplay.getWidth()||videoHeight>currentDisplay.getHeight()){
32              float heightRatio=(float)videoHeight/(float)currentDisplay.getHeight();
33              float widthRatio=(float)videoWidth/(float)currentDisplay.getWidth();
34              if(heightRatio>1||widthRatio>1){
35                  if(heightRatio>widthRatio){
36                      videoHeight=(int)Math.ceil((float)videoHeight/(float)heightRatio);
37                      videoWidth=(int)Math.ceil((float)videoWidth/(float)heightRatio);
38                  }else{
39                      videoHeight=(int)Math.ceil((float)videoHeight/(float)widthRatio);
40                      videoWidth=(int)Math.ceil((float)videoWidth/(float)widthRatio);
41                  }
42              }
43          }
44          surfaceView.setLayoutParams(new LinearLayout.LayoutParams(videoWidth,videoHeight));
45          controller.setMediaPlayer(this);
46          controller.setAnchorView(this.findViewById(R.id.MainView));
47          controller.setEnabled(true);
48          controller.show();
49          mp.start();
50          statusView.setText("MediaPlayer Started");
51     }
52     @Override
53     public void onSeekComplete(MediaPlayer mp) {
54 
55     }
56     @Override
57     public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
58          videoWidth=mp.getVideoWidth();
59          videoHeight=mp.getVideoHeight();
60          
61          if(videoWidth>currentDisplay.getWidth()||videoHeight>currentDisplay.getHeight()){
62              float heightRatio=(float)videoHeight/(float)currentDisplay.getHeight();
63              float widthRatio=(float)videoWidth/(float)currentDisplay.getWidth();
64              if(heightRatio>1||widthRatio>1){
65                  if(heightRatio>widthRatio){
66                      videoHeight=(int)Math.ceil((float)videoHeight/(float)heightRatio);
67                      videoWidth=(int)Math.ceil((float)videoWidth/(float)heightRatio);
68                  }else{
69                      videoHeight=(int)Math.ceil((float)videoHeight/(float)widthRatio);
70                      videoWidth=(int)Math.ceil((float)videoWidth/(float)widthRatio);
71                  }
72              }
73          }
74          surfaceView.setLayoutParams(new LinearLayout.LayoutParams(videoWidth,videoHeight));
75     }

    由于活动实现了OnBufferingUpdateListener,并注册为MediaPlayer的监听器,因此当下载缓冲媒体时,将定期调用以下方法。缓冲将发生在准备阶段(调用onPrepareAsync或onPrepare方法之后)。

 1     @Override
 2     public void onBufferingUpdate(MediaPlayer mp, int percent) {
 3         statusView.setText("MediaPlayer Buffering:"+percent+"%");
 4     }
 5 
 6     @Override
 7     public void start() {
 8         mediaPlayer.start();
 9     }
10 
11     @Override
12     public void pause() {
13        if(mediaPlayer.isPlaying()){
14            mediaPlayer.pause();
15        }
16     }
17 
18     @Override
19     public int getDuration() {
20         return mediaPlayer.getDuration();
21     }
22 
23     @Override
24     public int getCurrentPosition() {
25         return mediaPlayer.getCurrentPosition();
26     }
27 
28     @Override
29     public void seekTo(int pos) {
30         mediaPlayer.seekTo(pos);
31     }
32 
33     @Override
34     public boolean isPlaying() {
35         return mediaPlayer.isPlaying();
36     }
37 
38     @Override
39     public int getBufferPercentage() {
40         return 0;
41     }
42 
43     @Override
44     public boolean canPause() {
45         return false;
46     }
47 
48     @Override
49     public boolean canSeekBackward() {
50         return false;
51     }
52 
53     @Override
54     public boolean canSeekForward() {
55         return false;
56     }
57 
58     @Override
59     public int getAudioSessionId() {
60         return 0;
61     }
62     @Override
63     public boolean onTouch(View v, MotionEvent event) {
64         if(controller.isShowing()){
65             controller.hide();
66         }else{
67             controller.show();    
68         }
69         return false;
70     }
71 }

 

posted on 2014-09-05 09:09  宁静致远,一览众山小  阅读(352)  评论(0编辑  收藏  举报

导航