android之VideoView和视频播放View的扩展

android之VideoView和视频播放View的扩展
http://www.2cto.com/kf/201208/148912.html

1.概念及扩展   VideoView 是android 系统提供的一个媒体播放显示和控制的控件。其结构层次如下:   原型:VideoView extends SurfaceView implements MediaController.MediaPlayerControl   类结构:       java.lang.Object         ↳ android.view.View           ↳ android.view.SurfaceView             ↳ android.widget.VideoView   通过VideoView 的原型可知:如果构建更为复杂和有特色个性的视频View,需要继承SurfaceView 和实现MediaPlayerControl接口。其中SurfaceView 为显示提供支持,MediaPlayerControl则为媒体控制提供了支持。 2.案例 1)VideoView案例 (我们没有管理MediaPalyer的各种状态,这些状态都让VideoView给封装了,并且,当VideoView创建的时候,MediaPalyer对象将会创建,当VideoView对象销毁的时候,MediaPlayer对象将会释放。)

布局文件
  
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent"
     android:layout_height="fill_parent">
 <VideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"
     android:layout_centerInParent="true" />
 </LinearLayout>
 主程序:
 public class VideoPlayer extends Activity implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
     public static final String TAG = "VideoPlayer";
     private VideoView mVideoView;
     private Uri mUri;
     private int mPositionWhenPaused = -1;
 
    private MediaController mMediaController;
 
    @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
        setContentView(R.layout.main);
 
        //Set the screen to landscape.
         this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
 
        mVideoView = (VideoView)findViewById(R.id.video_view);
 
        //Video file
         mUri = Uri.parse(Environment.getExternalStorageDirectory() + "/1.3gp");
 
        //Create media controller,组件可以控制视频的播放,暂停,回复,seek等操作,不需要你实现
         mMediaController = new MediaController(this);
         mVideoView.setMediaController(mMediaController);
     }
 
    public void onStart() {
         // Play Video
         mVideoView.setVideoURI(mUri);
         mVideoView.start();
 
        super.onStart();
     }
 
    public void onPause() {
         // Stop video when the activity is pause.
         mPositionWhenPaused = mVideoView.getCurrentPosition();
         mVideoView.stopPlayback();
 
        super.onPause();
     }
 
    public void onResume() {
         // Resume video player
         if(mPositionWhenPaused >= 0) {
             mVideoView.seekTo(mPositionWhenPaused);
             mPositionWhenPaused = -1;
         }
 
        super.onResume();
     }
 
    public boolean onError(MediaPlayer player, int arg1, int arg2) {
         return false;
     }
 
    public void onCompletion(MediaPlayer mp) {
         this.finish();
     }
 }
 2)自定义VideoView
 和VideoView实现类似,继承了SurfaceView并且实现了MediaPlayerControl。
 public class CustomerVideoView extends SurfaceView implements
         MediaPlayerControl {
     private static String TAG = "customer.videoplayer";
     private boolean pause;
     private boolean seekBackward;
     private boolean seekForward;
     private Uri videoUri;
     private MediaPlayer mediaPlayer;
     private Context context;
     private OnPreparedListener onPreparedListener;
     private int videoWidth;
     private int videoHeight;
     private MediaController mediaController;
     protected SurfaceHolder surfaceHolder;
     private Callback surfaceHolderCallback = new SurfaceHolder.Callback() {
         public void surfaceChanged(SurfaceHolder holder, int format, int w,
                 int h) {
         }
         public void surfaceCreated(SurfaceHolder holder) {
             surfaceHolder = holder;
             if (mediaPlayer != null) {
                 mediaPlayer.setDisplay(surfaceHolder);
                 resume();
             } else {
                 openVideo();
             }
         }
         public void surfaceDestroyed(SurfaceHolder holder) {
             surfaceHolder = null;
             if (mediaController != null) {
                 mediaController.hide();
             }
             release(true);
         }
     };
     private void release(boolean cleartargetstate) {
         if (mediaPlayer != null) {
             mediaPlayer.reset();
             mediaPlayer.release();
             mediaPlayer = null;
         }
     }
     public void resume() {
         if (surfaceHolder == null) {
             return;
         }
         if (mediaPlayer != null) {
             return;
         }
         openVideo();
     }
     public CustomerVideoView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         this.context = context;
         this.initVideoView();
     }
     public CustomerVideoView(Context context, AttributeSet attrs) {
         super(context, attrs);
         this.context = context;
         this.initVideoView();
     }
     public CustomerVideoView(Context context) {
         super(context);
         this.context = context;
         this.initVideoView();
     }
     @Override
     public boolean canPause() {
         return this.pause;
     }
     @Override
     public boolean canSeekBackward() {
         return this.seekBackward;
     }
     @Override
     public boolean canSeekForward() {
         return this.seekForward;
     }
     @Override
     public int getBufferPercentage() {
         return 0;
     }
     @Override
     public int getCurrentPosition() {
         return mediaPlayer!=null?mediaPlayer.getCurrentPosition():0;
     }
     @Override
     public int getDuration() {
         return mediaPlayer!=null?mediaPlayer.getDuration():0;
     }
     @Override
     public boolean isPlaying() {
         return false;
     }
     @Override
     public void pause() {
     }
     @Override
     public void seekTo(int mSec) {
     }
     @Override
     public void start() {
     }
     public void setVideoURI(Uri uri) {
         this.videoUri = uri;
         openVideo();
         requestLayout();
         invalidate();
     }
     private void openVideo() {
         this.mediaPlayer = new MediaPlayer();
         try {
             this.mediaPlayer.setDataSource(this.context, this.videoUri);
         } catch (Exception e) {
             Log.e(TAG, e.getMessage());
             throw new RuntimeException(e);
         }
         this.mediaPlayer.prepareAsync();
         this.mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
         this.mediaPlayer.setOnPreparedListener(onPreparedListener);
         attachMediaController();
     }
     private void attachMediaController() {
         if (mediaPlayer != null && mediaController != null) {
             mediaController.setMediaPlayer(this);
             View anchorView = this.getParent() instanceof View ? (View) this
                     .getParent() : this;
             mediaController.setAnchorView(anchorView);
             mediaController.setEnabled(true);
         }
     }
     public void setMediaController(MediaController controller) {
         if (mediaController != null) {
             mediaController.hide();
         }
         mediaController = controller;
         attachMediaController();
     }
     public void setOnPreparedListener(OnPreparedListener onPreparedListener) {
         this.onPreparedListener = onPreparedListener;
     }
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = getDefaultSize(videoWidth, widthMeasureSpec);
         int height = getDefaultSize(videoHeight, heightMeasureSpec);
         if (videoWidth > 0 && videoHeight > 0) {
             if (videoWidth * height > width * videoHeight) {
                 height = width * videoHeight / videoWidth;
             } else if (videoWidth * height < width * videoHeight) {
                 width = height * videoWidth / videoHeight;
             }
         }
         Log.i(TAG, "setting size: " + width + ‘x’ + height);
         setMeasuredDimension(width, height);
     }
     private void initVideoView() {
         videoWidth = 0;
         videoHeight = 0;
         getHolder().addCallback(surfaceHolderCallback);
         getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
         setFocusable(true);
         setFocusableInTouchMode(true);
         requestFocus();
     }
 }

  一般情况下,android界面的绘制和更新,要交给主ui线程来操作,通过Handler机制。但是播放视频,需要比较优先和实时的改变和绘制界面。android提供了使用单独线程绘制UI的机制,就是SurfaceView。使用SurfaceView,需要实现SurfaceHolder.Callback接口: surfaceCreated,在Surface(SurfaceView内部包含一个Surface实例)创建后,会立即调用该方法,可在该方法中做绘制界面相关的初始化工作; surfaceChanged,当Surface的状态发生变化,比如大小,会调用该方法,在surfaceCreated方法调用过至少会调用一次该方法; surfaceDestroyed,当销毁Surface的时候调用。   开发者不能直接操作Surface实例,要通过SurfaceHandler,在SurfaceView中可以通过getHandler方法获取到SurfaceHandler实例。 SurfaceHander有一些类型,用来标识Surface实例界面数据来源,可以通过setType来操作: SURFACE_TYPE_NORMAL:RAM缓存的原生数据 SURFACE_TYPE_HARDWARE:通过DMA,direct memory access,就是直接写屏技术获取到的数据,或者其他硬件加速的数据 SURFACE_TYPE_GPU:通过GPU加速的数据 SURFACE_TYPE_PUSH_BUFFERS:标识数据来源于其他对象,比如照相机,比如视频播放服务器(android内部有视频播放的服务器,所有播放视频相当于客户端)

  CustomerVideoView的构造方法,使用超类的构造方法。都会执行initVideoView()方法用来初始化界面和参数。另外一个主要的内容是openVideo()方法: mediaPlayer.prepareAsync(),用来异步准备播放,另外还有个prepare()方法,是同步的,也就是全部下载完毕才能播放,显然,在播放网上视频的时候需要用前者; 通过attachMediaController()方法,把控制条附加到播放视频的SurfaceView上,这里实现的不完全,因此还不能使用,仅仅是把MediaPlayerControl实例通过setMediaPlayer方法设置一下,供OnPreparedListener用来得到加载成功的回调,另外供外面代码调用得到视频的时长和当前时长。

posted @ 2014-03-28 11:34  萧萧  阅读(164)  评论(0)    收藏  举报