用vitamio打造自己的视频播放器

对于视频播放器,市面上也有很多,也做得比较好,写这篇文章目的只是为了让大家了解播放器的开发过程,也让自己再次熟悉下这部分的代码。有些播放器用SDL进行视频渲染,但是这篇文章只写基础。用vitamio是为了支持多种视频格式如swf、flv、avi、asf、f4v、mkv、mov、rmvb、tp、ts、wmv、m3u8等市面上的视频格式都涵盖了

接下来就是代码开始了。

对于播放器首先要有播放视图,这里抽象为VideoView继承SurfaceView,所有的播放逻辑都这这里。其次有控制视频播放的接口如暂停、播放、进度条,滑动设置视频音量大小等,这里抽象为MediaController继承FrameLayout。

VideoView代码如下:

package com.example.videotest.widget;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.AudioManager;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;

import com.example.videotest.R;
import com.example.videotest.widget.MediaController.MediaPlayerControl;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;

import io.vov.utils.Log;
import io.vov.vitamio.MediaPlayer;
import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener;
import io.vov.vitamio.MediaPlayer.OnCompletionListener;
import io.vov.vitamio.MediaPlayer.OnErrorListener;
import io.vov.vitamio.MediaPlayer.OnInfoListener;
import io.vov.vitamio.MediaPlayer.OnPreparedListener;
import io.vov.vitamio.MediaPlayer.OnSeekCompleteListener;
import io.vov.vitamio.MediaPlayer.OnSubtitleUpdateListener;
import io.vov.vitamio.MediaPlayer.OnVideoSizeChangedListener;


public class VideoView extends SurfaceView implements MediaPlayerControl{

   private Uri mUri;
   private long mDuration;
   /**
    * 视频状态机
    */
   private static final int STATE_ERROR = -1;
   private static final int STATE_IDLE = 0;
   private static final int STATE_PREPARING = 1;
   private static final int STATE_PREPARED = 2;
   private static final int STATE_PLAYING = 3;
   private static final int STATE_PAUSED = 4;
   private static final int STATE_PLAYBACK_COMPLETED = 5;
   private static final int STATE_SUSPEND = 6;
   private static final int STATE_RESUME = 7;
   private static final int STATE_SUSPEND_UNSUPPORTED = 8;

   private int mCurrentState = STATE_IDLE;
   private int mTargetState = STATE_IDLE;

   private float mAspectRatio = 0;
   private int mVideoLayout = VIDEO_LAYOUT_SCALE;
   public static final int VIDEO_LAYOUT_ORIGIN = 0;
   public static final int VIDEO_LAYOUT_SCALE = 1;
   public static final int VIDEO_LAYOUT_STRETCH = 2;
   public static final int VIDEO_LAYOUT_ZOOM = 3;

   private SurfaceHolder mSurfaceHolder = null;
   private MediaPlayer mMediaPlayer = null;
   private int mVideoWidth;
   private int mVideoHeight;
   private float mVideoAspectRatio;
   private int mSurfaceWidth;
   private int mSurfaceHeight;
   private MediaController mMediaController;
   private OnCompletionListener mOnCompletionListener;
   private OnPreparedListener mOnPreparedListener;
   private OnErrorListener mOnErrorListener;
   private OnSeekCompleteListener mOnSeekCompleteListener;
   private OnSubtitleUpdateListener mOnSubtitleUpdateListener;
   private OnInfoListener mOnInfoListener;
   private OnBufferingUpdateListener mOnBufferingUpdateListener;
   private int mCurrentBufferPercentage;
   private long mSeekWhenPrepared;
   private boolean mCanPause = true;
   private boolean mCanSeekBack = true;
   private boolean mCanSeekForward = true;
   private Context mContext;

   public VideoView(Context context) {
      super(context);
      initVideoView(context);
   }

   public VideoView(Context context, AttributeSet attrs) {
      this(context, attrs, 0);
   }

   public VideoView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      initVideoView(context);
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
      int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
      setMeasuredDimension(width, height);
   }

   /**
    * Set the display options
    * 
    * @param layout <ul>
    * <li>{@link #VIDEO_LAYOUT_ORIGIN}
    * <li>{@link #VIDEO_LAYOUT_SCALE}
    * <li>{@link #VIDEO_LAYOUT_STRETCH}
    * <li>{@link #VIDEO_LAYOUT_ZOOM}
    * </ul>
    * @param aspectRatio 视频宽高比,将自动检测
    */
   public void setVideoLayout(int layout, float aspectRatio) {
      LayoutParams lp = getLayoutParams();
      DisplayMetrics disp = mContext.getResources().getDisplayMetrics();
      int windowWidth = disp.widthPixels, windowHeight = disp.heightPixels;
      float windowRatio = windowWidth / (float) windowHeight;
      float videoRatio = aspectRatio <= 0.01f ? mVideoAspectRatio : aspectRatio;
      mSurfaceHeight = mVideoHeight;
      mSurfaceWidth = mVideoWidth;
      if (VIDEO_LAYOUT_ORIGIN == layout && mSurfaceWidth < windowWidth && mSurfaceHeight < windowHeight) {
         lp.width = (int) (mSurfaceHeight * videoRatio);
         lp.height = mSurfaceHeight;
      } else if (layout == VIDEO_LAYOUT_ZOOM) {
         lp.width = windowRatio > videoRatio ? windowWidth : (int) (videoRatio * windowHeight);
         lp.height = windowRatio < videoRatio ? windowHeight : (int) (windowWidth / videoRatio);
      } else {
//       boolean full = layout == VIDEO_LAYOUT_STRETCH;
//       lp.width = (full || windowRatio < videoRatio) ? windowWidth : (int) (videoRatio * windowHeight);
//       lp.height = (full || windowRatio > videoRatio) ? windowHeight : (int) (windowWidth / videoRatio);
      }
      setLayoutParams(lp);
      getHolder().setFixedSize(mSurfaceWidth, mSurfaceHeight);
      Log.d("VIDEO: %dx%dx%f, Surface: %dx%d, LP: %dx%d, Window: %dx%dx%f", mVideoWidth, mVideoHeight, mVideoAspectRatio, mSurfaceWidth, mSurfaceHeight, lp.width, lp.height, windowWidth, windowHeight, windowRatio);
      mVideoLayout = layout;
      mAspectRatio = aspectRatio;
   }

   private void initVideoView(Context ctx) {
      mContext = ctx;
      mVideoWidth = 0;
      mVideoHeight = 0;
      getHolder().addCallback(mSHCallback);
      setFocusable(true);
      setFocusableInTouchMode(true);
      requestFocus();
      mCurrentState = STATE_IDLE;
      mTargetState = STATE_IDLE;
      if (ctx instanceof Activity)
         ((Activity) ctx).setVolumeControlStream(AudioManager.STREAM_MUSIC);
   }

   public boolean isValid() {
      return (mSurfaceHolder != null && mSurfaceHolder.getSurface().isValid());
   }

   public void setVideoPath(String path) {
      setVideoURI(Uri.parse(path));
   }

   public void setVideoURI(Uri uri) {
      mUri = uri;
      mSeekWhenPrepared = 0;
      openVideo();
      requestLayout();
      invalidate();
   }

   public void stopPlayback() {
      if (mMediaPlayer != null) {
         mMediaPlayer.stop();
         mMediaPlayer.release();
         mMediaPlayer = null;
         mCurrentState = STATE_IDLE;
         mTargetState = STATE_IDLE;
      }
   }

   private void openVideo() {
      if (mUri == null || mSurfaceHolder == null)
         return;

      Intent i = new Intent("com.android.music.musicservicecommand");
      i.putExtra("command", "pause");
      mContext.sendBroadcast(i);

      release(false);
      try {
         mDuration = -1;
         mCurrentBufferPercentage = 0;
         mMediaPlayer = new MediaPlayer(mContext);
         mMediaPlayer.setOnPreparedListener(mPreparedListener);
         mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
         mMediaPlayer.setOnCompletionListener(mCompletionListener);
         mMediaPlayer.setOnErrorListener(mErrorListener);
         mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
         mMediaPlayer.setOnInfoListener(mInfoListener);
         mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
         mMediaPlayer.setOnSubtitleUpdateListener(mSubtitleUpdateListener);
         mMediaPlayer.setDataSource(mContext, mUri);
         mMediaPlayer.setDisplay(mSurfaceHolder);
         mMediaPlayer.setScreenOnWhilePlaying(true);
         mMediaPlayer.prepareAsync();
         mCurrentState = STATE_PREPARING;
         attachMediaController();
      } catch (IOException ex) {
         Log.e("Unable to open content: " + mUri, ex);
         mCurrentState = STATE_ERROR;
         mTargetState = STATE_ERROR;
         mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
         return;
      } catch (IllegalArgumentException ex) {
         Log.e("Unable to open content: " + mUri, ex);
         mCurrentState = STATE_ERROR;
         mTargetState = STATE_ERROR;
         mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
         return;
      }
   }

   public void setMediaController(MediaController controller) {
      if (mMediaController != null)
         mMediaController.hide();
      mMediaController = controller;
      attachMediaController();
   }

// View mView;
// public void setView(View view){
//    this.mView = view;
// }
   
   private void attachMediaController() {
      if (mMediaPlayer != null && mMediaController != null) {
         mMediaController.setMediaPlayer(this);
         //View anchorView = ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.vedio_play_activity, null).findViewById(R.id.media_player_layout);
         
         View anchorView = this.getParent() instanceof View ? (View) this.getParent() : this;
         mMediaController.setAnchorView(anchorView);
         mMediaController.setEnabled(isInPlaybackState());

         if (mUri != null) {
            List<String> paths = mUri.getPathSegments();
            String name = paths == null || paths.isEmpty() ? "null" : paths.get(paths.size() - 1);
            mMediaController.setFileName(name);
         }
      }
   }

   OnVideoSizeChangedListener mSizeChangedListener = new OnVideoSizeChangedListener() {
      @Override
    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
         Log.d("onVideoSizeChanged: (%dx%d)", width, height);
         mVideoWidth = mp.getVideoWidth();
         mVideoHeight = mp.getVideoHeight();
         mVideoAspectRatio = mp.getVideoAspectRatio();
         if (mVideoWidth != 0 && mVideoHeight != 0)
            setVideoLayout(mVideoLayout, mAspectRatio);
      }
   };

   OnPreparedListener mPreparedListener = new OnPreparedListener() {
      @Override
    public void onPrepared(MediaPlayer mp) {
         Log.d("onPrepared");
         mCurrentState = STATE_PREPARED;
         mTargetState = STATE_PLAYING;

         if (mOnPreparedListener != null)
            mOnPreparedListener.onPrepared(mMediaPlayer);
         if (mMediaController != null)
            mMediaController.setEnabled(true);
         mVideoWidth = mp.getVideoWidth();
         mVideoHeight = mp.getVideoHeight();
         mVideoAspectRatio = mp.getVideoAspectRatio();

         long seekToPosition = mSeekWhenPrepared;

         if (seekToPosition != 0)
            seekTo(seekToPosition);
         if (mVideoWidth != 0 && mVideoHeight != 0) {
            setVideoLayout(mVideoLayout, mAspectRatio);
            if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
               if (mTargetState == STATE_PLAYING) {
                  start();
                  if (mMediaController != null)
                     mMediaController.show();
               } else if (!isPlaying() && (seekToPosition != 0 || getCurrentPosition() > 0)) {
                  if (mMediaController != null)
                     mMediaController.show(0);
               }
            }
         } else if (mTargetState == STATE_PLAYING) {
            start();
         }
      }
   };

   private OnCompletionListener mCompletionListener = new OnCompletionListener() {
      @Override
    public void onCompletion(MediaPlayer mp) {
         Log.d("onCompletion");
         mCurrentState = STATE_PLAYBACK_COMPLETED;
         mTargetState = STATE_PLAYBACK_COMPLETED;
         if (mMediaController != null)
            mMediaController.hide();
         if (mOnCompletionListener != null)
            mOnCompletionListener.onCompletion(mMediaPlayer);
      }
   };

   private OnErrorListener mErrorListener = new OnErrorListener() {
      @Override
    public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
         Log.d("Error: %d, %d", framework_err, impl_err);
         mCurrentState = STATE_ERROR;
         mTargetState = STATE_ERROR;
         if (mMediaController != null)
            mMediaController.hide();

         if (mOnErrorListener != null) {
            if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err))
               return true;
         }

         if (getWindowToken() != null) {
            int message = framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK ? R.string.VideoView_error_text_invalid_progressive_playback : R.string.VideoView_error_text_unknown;

            new AlertDialog.Builder(mContext).setTitle(R.string.VideoView_error_title).setMessage(message).setPositiveButton(R.string.VideoView_error_button, new DialogInterface.OnClickListener() {
               @Override
          public void onClick(DialogInterface dialog, int whichButton) {
                  if (mOnCompletionListener != null)
                     mOnCompletionListener.onCompletion(mMediaPlayer);
               }
            }).setCancelable(false).show();
         }
         return true;
      }
   };

   private OnBufferingUpdateListener mBufferingUpdateListener = new OnBufferingUpdateListener() {
      @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
         mCurrentBufferPercentage = percent;
         if (mOnBufferingUpdateListener != null)
            mOnBufferingUpdateListener.onBufferingUpdate(mp, percent);
      }
   };

   private OnInfoListener mInfoListener = new OnInfoListener() {
      @Override
      public boolean onInfo(MediaPlayer mp, int what, int extra) {
         Log.d("onInfo: (%d, %d)", what, extra);
         if (mOnInfoListener != null) {
            mOnInfoListener.onInfo(mp, what, extra);
         } else if (mMediaPlayer != null) {
            if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START)
               mMediaPlayer.pause();
            else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END)
               mMediaPlayer.start();
         }

         return true;
      }
   };

   private OnSeekCompleteListener mSeekCompleteListener = new OnSeekCompleteListener() {
      @Override
      public void onSeekComplete(MediaPlayer mp) {
         Log.d("onSeekComplete");
         if (mOnSeekCompleteListener != null)
            mOnSeekCompleteListener.onSeekComplete(mp);
      }
   };

   private OnSubtitleUpdateListener mSubtitleUpdateListener = new OnSubtitleUpdateListener() {
      @Override
      public void onSubtitleUpdate(byte[] pixels, int width, int height) {
         Log.i("onSubtitleUpdate: bitmap subtitle, %dx%d", width, height);
         if (mOnSubtitleUpdateListener != null)
            mOnSubtitleUpdateListener.onSubtitleUpdate(pixels, width, height);
      }

      @Override
      public void onSubtitleUpdate(String text) {
         Log.i("onSubtitleUpdate: %s", text);
         if (mOnSubtitleUpdateListener != null)
            mOnSubtitleUpdateListener.onSubtitleUpdate(text);
      }
   };

   public void setOnPreparedListener(OnPreparedListener l) {
      mOnPreparedListener = l;
   }

   public void setOnCompletionListener(OnCompletionListener l) {
      mOnCompletionListener = l;
   }

   public void setOnErrorListener(OnErrorListener l) {
      mOnErrorListener = l;
   }

   public void setOnBufferingUpdateListener(OnBufferingUpdateListener l) {
      mOnBufferingUpdateListener = l;
   }

   public void setOnSeekCompleteListener(OnSeekCompleteListener l) {
      mOnSeekCompleteListener = l;
   }

   public void setOnSubtitleUpdateListener(OnSubtitleUpdateListener l) {
      mOnSubtitleUpdateListener = l;
   }

   public void setOnInfoListener(OnInfoListener l) {
      mOnInfoListener = l;
   }

   SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() {
      @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
         mSurfaceWidth = w;
         mSurfaceHeight = h;
         boolean isValidState = (mTargetState == STATE_PLAYING);
         boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h);
         if (mMediaPlayer != null && isValidState && hasValidSize) {
            if (mSeekWhenPrepared != 0)
               seekTo(mSeekWhenPrepared);
            start();
            if (mMediaController != null) {
               if (mMediaController.isShowing())
                  mMediaController.hide();
               mMediaController.show();
            }
         }
      }

      @Override
    public void surfaceCreated(SurfaceHolder holder) {
         mSurfaceHolder = holder;
         if (mMediaPlayer != null && mCurrentState == STATE_SUSPEND && mTargetState == STATE_RESUME) {
            mMediaPlayer.setDisplay(mSurfaceHolder);
            resume();
         } else {
            openVideo();
         }
      }

      @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
         mSurfaceHolder = null;
         if (mMediaController != null)
            mMediaController.hide();
         if (mCurrentState != STATE_SUSPEND)
            release(true);
      }
   };

   private void release(boolean cleartargetstate) {
      if (mMediaPlayer != null) {
         mMediaPlayer.reset();
         mMediaPlayer.release();
         mMediaPlayer = null;
         mCurrentState = STATE_IDLE;
         if (cleartargetstate)
            mTargetState = STATE_IDLE;
      }
   }

   @Override
   public boolean onTouchEvent(MotionEvent ev) {
      if (isInPlaybackState() && mMediaController != null)
         toggleMediaControlsVisiblity();
      return false;
   }

   @Override
   public boolean onTrackballEvent(MotionEvent ev) {
      if (isInPlaybackState() && mMediaController != null)
         toggleMediaControlsVisiblity();
      return false;
   }

   @Override
   public boolean onKeyDown(int keyCode, KeyEvent event) {
      boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_MENU && keyCode != KeyEvent.KEYCODE_CALL && keyCode != KeyEvent.KEYCODE_ENDCALL;
      if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
         if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE) {
            if (mMediaPlayer.isPlaying()) {
               pause();
               mMediaController.show();
            } else {
               start();
               mMediaController.hide();
            }
            return true;
         } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP && mMediaPlayer.isPlaying()) {
            pause();
            mMediaController.show();
         } else {
            toggleMediaControlsVisiblity();
         }
      }

      return super.onKeyDown(keyCode, event);
   }

   private void toggleMediaControlsVisiblity() {
      if (mMediaController.isShowing()) {
         mMediaController.hide();
      } else {
         mMediaController.show();
      }
   }

   @Override
  public void start() {
      if (isInPlaybackState()) {
         mMediaPlayer.start();
         mCurrentState = STATE_PLAYING;
      }
      mTargetState = STATE_PLAYING;
   }

   @Override
  public void pause() {
      if (isInPlaybackState()) {
         if (mMediaPlayer.isPlaying()) {
            mMediaPlayer.pause();
            mCurrentState = STATE_PAUSED;
         }
      }
      mTargetState = STATE_PAUSED;
   }

   public void suspend() {
      if (isInPlaybackState()) {
         release(false);
         mCurrentState = STATE_SUSPEND_UNSUPPORTED;
         Log.d("Unable to suspend video. Release MediaPlayer.");
      }
   }

   public void resume() {
      if (mSurfaceHolder == null && mCurrentState == STATE_SUSPEND) {
         mTargetState = STATE_RESUME;
      } else if (mCurrentState == STATE_SUSPEND_UNSUPPORTED) {
         openVideo();
      }
   }

   @Override
  public long getDuration() {
      if (isInPlaybackState()) {
         if (mDuration > 0)
            return mDuration;
         mDuration = mMediaPlayer.getDuration();
         return mDuration;
      }
      mDuration = -1;
      return mDuration;
   }

   @Override
  public long getCurrentPosition() {
      if (isInPlaybackState())
         return mMediaPlayer.getCurrentPosition();
      return 0;
   }

   @Override
  public void seekTo(long msec) {
      if (isInPlaybackState()) {
         mMediaPlayer.seekTo(msec);
         mSeekWhenPrepared = 0;
      } else {
         mSeekWhenPrepared = msec;
      }
   }

   @Override
  public boolean isPlaying() {
      return isInPlaybackState() && mMediaPlayer.isPlaying();
   }

   @Override
  public int getBufferPercentage() {
      if (mMediaPlayer != null)
         return mCurrentBufferPercentage;
      return 0;
   }

   public void setVolume(float leftVolume, float rightVolume) {
      if (mMediaPlayer != null)
         mMediaPlayer.setVolume(leftVolume, rightVolume);
   }

   public int getVideoWidth() {
      return mVideoWidth;
   }

   public int getVideoHeight() {
      return mVideoHeight;
   }

   public float getVideoAspectRatio() {
      return mVideoAspectRatio;
   }

   public void setVideoQuality(int quality) {
      if (mMediaPlayer != null)
         mMediaPlayer.setVideoQuality(quality);
   }

   public void setBufferSize(int bufSize) {
      if (mMediaPlayer != null)
         mMediaPlayer.setBufferSize(bufSize);
   }

   public boolean isBuffering() {
      if (mMediaPlayer != null)
         return mMediaPlayer.isBuffering();
      return false;
   }

   public void setMetaEncoding(String encoding) {
      if (mMediaPlayer != null)
         mMediaPlayer.setMetaEncoding(encoding);
   }

   public String getMetaEncoding() {
      if (mMediaPlayer != null)
         return mMediaPlayer.getMetaEncoding();
      return null;
   }

   public HashMap<String, Integer> getAudioTrackMap(String encoding) {
      if (mMediaPlayer != null)
         return mMediaPlayer.getAudioTrackMap(encoding);
      return null;
   }

   public int getAudioTrack() {
      if (mMediaPlayer != null)
         return mMediaPlayer.getAudioTrack();
      return -1;
   }

   public void setAudioTrack(int audioIndex) {
      if (mMediaPlayer != null)
         mMediaPlayer.setAudioTrack(audioIndex);
   }

   public void setSubShown(boolean shown) {
      if (mMediaPlayer != null)
         mMediaPlayer.setSubShown(shown);
   }

   public void setSubEncoding(String encoding) {
      if (mMediaPlayer != null)
         mMediaPlayer.setSubEncoding(encoding);
   }

   public int getSubLocation() {
      if (mMediaPlayer != null)
         return mMediaPlayer.getSubLocation();
      return -1;
   }

   public void setSubPath(String subPath) {
      if (mMediaPlayer != null)
         mMediaPlayer.setSubPath(subPath);
   }

   public String getSubPath() {
      if (mMediaPlayer != null)
         return mMediaPlayer.getSubPath();
      return null;
   }

   public void setSubTrack(int trackId) {
      if (mMediaPlayer != null)
         mMediaPlayer.setSubTrack(trackId);
   }

   public int getSubTrack() {
      if (mMediaPlayer != null)
         return mMediaPlayer.getSubTrack();
      return -1;
   }

   public HashMap<String, Integer> getSubTrackMap(String encoding) {
      if (mMediaPlayer != null)
         return mMediaPlayer.getSubTrackMap(encoding);
      return null;
   }

   protected boolean isInPlaybackState() {
      return (mMediaPlayer != null && mCurrentState != STATE_ERROR && mCurrentState != STATE_IDLE && mCurrentState != STATE_PREPARING);
   }

   @Override
  public boolean canPause() {
      return mCanPause;
   }

   @Override
  public boolean canSeekBackward() {
      return mCanSeekBack;
   }

   @Override
  public boolean canSeekForward() {
      return mCanSeekForward;
   }
}
代码都比较好理解。

接下来是控制器

package com.example.videotest.widget;

import com.example.videotest.R;

import io.vov.utils.Log;
import io.vov.utils.StringUtils;

import android.content.Context;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;


public class MediaController extends FrameLayout {
    private MediaPlayerControl mPlayer;
    private Context mContext;
    private PopupWindow mWindow;
    private int mAnimStyle;
    private View mAnchor;
    private View mRoot;
    private ProgressBar mProgress;
    private TextView mEndTime, mCurrentTime;
    private TextView mFileName;
    private OutlineTextView mInfoView;
    private String mTitle;
    private long mDuration;
    private boolean mShowing;
    private boolean mDragging;
    private boolean mInstantSeeking = true;
    private static final int sDefaultTimeout = 3000;
    private static final int FADE_OUT = 1;
    private static final int SHOW_PROGRESS = 2;
    private boolean mFromXml = false;
    private ImageButton mPauseButton;

    private AudioManager mAM;

    public MediaController(Context context, AttributeSet attrs) {
        super(context, attrs);
        mRoot = this;
        mFromXml = true;
        initController(context);
    }

    public MediaController(Context context) {
        super(context);
        if (!mFromXml && initController(context))
            initFloatingWindow();
    }

    private boolean initController(Context context) {
        mContext = context;
        mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
        return true;
    }

    @Override
    public void onFinishInflate() {
        if (mRoot != null)
            initControllerView(mRoot);
    }

    private void initFloatingWindow() {
        mWindow = new PopupWindow(mContext);
        mWindow.setFocusable(false);
        mWindow.setBackgroundDrawable(null);
        mWindow.setOutsideTouchable(true);
        mAnimStyle = android.R.style.Animation;
    }

    /**
     * Set the view that acts as the anchor for the control view. This can for
     * example be a VideoView, or your Activity's main view.
     *
     * @param view The view to which to anchor the controller when it is visible.
     */
    public void setAnchorView(View view) {
        mAnchor = view;
        if (!mFromXml) {
            removeAllViews();
            mRoot = makeControllerView();
            mWindow.setContentView(mRoot);
            mWindow.setWidth(android.view.ViewGroup.LayoutParams.MATCH_PARENT);
            mWindow.setHeight(android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        initControllerView(mRoot);
    }

    /**
     *
     * @return The controller view.
     */
    protected View makeControllerView() {
        return ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.mediacontroller, this);
    }

    private void initControllerView(View v) {
        mPauseButton = (ImageButton) v.findViewById(R.id.mediacontroller_play_pause);
        if (mPauseButton != null) {
            mPauseButton.requestFocus();
            mPauseButton.setOnClickListener(mPauseListener);
        }

        mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_seekbar);
        if (mProgress != null) {
            if (mProgress instanceof SeekBar) {
                SeekBar seeker = (SeekBar) mProgress;
                seeker.setOnSeekBarChangeListener(mSeekListener);
                seeker.setThumbOffset(1);
            }
            mProgress.setMax(1000);
        }

        mEndTime = (TextView) v.findViewById(R.id.mediacontroller_time_total);
        mCurrentTime = (TextView) v.findViewById(R.id.mediacontroller_time_current);
        mFileName = (TextView) v.findViewById(R.id.mediacontroller_file_name);
        if (mFileName != null)
            mFileName.setText(mTitle);
    }

    public void setMediaPlayer(MediaPlayerControl player) {
        mPlayer = player;
        updatePausePlay();
    }

    /**
     *
     * @param seekWhenDragging
     */
    public void setInstantSeeking(boolean seekWhenDragging) {
        mInstantSeeking = seekWhenDragging;
    }

    public void show() {
        show(sDefaultTimeout);
    }

    /**
     *
     * @param name
     */
    public void setFileName(String name) {
        mTitle = name;
        if (mFileName != null)
            mFileName.setText(mTitle);
    }

    /**
     * MediaController
     *
     * @param v
     */
    public void setInfoView(OutlineTextView v) {
        mInfoView = v;
    }

    private void disableUnsupportedButtons() {
        try {
            if (mPauseButton != null && !mPlayer.canPause())
                mPauseButton.setEnabled(false);
        } catch (IncompatibleClassChangeError ex) {
        }
    }

    /**
     * @param animationStyle 控制器出现时使用动画风格
     *                            和消失。设置为-1为默认的动画,0表示没有动画,或
     *                            一个显式动画资源标识符。
     */
    public void setAnimationStyle(int animationStyle) {
        mAnimStyle = animationStyle;
    }

    /**
     * 在屏幕上显示控制器。它会显示timeout长时间后自动消失
     *
     * @param timeout
     */
    public void show(int timeout) {
        if (!mShowing && mAnchor != null && mAnchor.getWindowToken() != null) {
            if (mPauseButton != null)
                mPauseButton.requestFocus();
            disableUnsupportedButtons();

            if (mFromXml) {
                setVisibility(View.VISIBLE);
            } else {
//          int[] location = new int[2];
//
//          mAnchor.getLocationOnScreen(location);
//          Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight());

                mWindow.setAnimationStyle(mAnimStyle);
                mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, mAnchor.getWidth(), mAnchor.getHeight());
            }
            mShowing = true;
            if (mShownListener != null)
                mShownListener.onShown();
        }
        updatePausePlay();
        mHandler.sendEmptyMessage(SHOW_PROGRESS);

        if (timeout != 0) {
            mHandler.removeMessages(FADE_OUT);
            mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT), timeout);
        }
    }

    public boolean isShowing() {
        return mShowing;
    }

    /**
     * 隐藏控制条
     */
    public void hide() {
        if (mAnchor == null)
            return;

        if (mShowing) {
            try {
                mHandler.removeMessages(SHOW_PROGRESS);
                if (mFromXml)
                    setVisibility(View.GONE);
                else
                    mWindow.dismiss();
            } catch (IllegalArgumentException ex) {
                Log.d("MediaController already removed");
            }
            mShowing = false;
            if (mHiddenListener != null)
                mHiddenListener.onHidden();
        }
    }

    public interface OnShownListener {
        public void onShown();
    }

    private OnShownListener mShownListener;

    public void setOnShownListener(OnShownListener l) {
        mShownListener = l;
    }

    public interface OnHiddenListener {
        public void onHidden();
    }

    private OnHiddenListener mHiddenListener;

    public void setOnHiddenListener(OnHiddenListener l) {
        mHiddenListener = l;
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            long pos;
            switch (msg.what) {
                case FADE_OUT:
                    //hide();
                    break;
                case SHOW_PROGRESS:
                    pos = setProgress();
                    if (!mDragging && mShowing) {
                        msg = obtainMessage(SHOW_PROGRESS);
                        sendMessageDelayed(msg, 1000 - (pos % 1000));
                        updatePausePlay();
                    }
                    break;
            }
        }
    };

    private long setProgress() {
        if (mPlayer == null || mDragging)
            return 0;

        long position = mPlayer.getCurrentPosition();
        long duration = mPlayer.getDuration();
        if (mProgress != null) {
            if (duration > 0) {
                long pos = 1000L * position / duration;
                mProgress.setProgress((int) pos);
            }
            int percent = mPlayer.getBufferPercentage();
            mProgress.setSecondaryProgress(percent * 10);
        }

        mDuration = duration;

        if (mEndTime != null)
            mEndTime.setText(StringUtils.generateTime(mDuration));
        if (mCurrentTime != null)
            mCurrentTime.setText(StringUtils.generateTime(position));

        return position;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        show(sDefaultTimeout);
        return true;
    }

    @Override
    public boolean onTrackballEvent(MotionEvent ev) {
        show(sDefaultTimeout);
        return false;
    }

    /**
     * 接收事件
     *
     * @param event
     * @return
     */
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        int keyCode = event.getKeyCode();
        if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
            doPauseResume();
            show(sDefaultTimeout);
            if (mPauseButton != null)
                mPauseButton.requestFocus();
            return true;
        } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
            if (mPlayer.isPlaying()) {
                mPlayer.pause();
                updatePausePlay();
            }
            return true;
        } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
            hide();
            return true;
        } else {
            show(sDefaultTimeout);
        }
        return super.dispatchKeyEvent(event);
    }

    private View.OnClickListener mPauseListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            doPauseResume();
            show(sDefaultTimeout);
        }
    };

    private void updatePausePlay() {
        if (mRoot == null || mPauseButton == null)
            return;

        if (mPlayer.isPlaying())
            mPauseButton.setImageResource(R.drawable.mediacontroller_pause_button);
        else
            mPauseButton.setImageResource(R.drawable.mediacontroller_play_button);
    }

    private void doPauseResume() {
        if (mPlayer.isPlaying())
            mPlayer.pause();
        else
            mPlayer.start();
        updatePausePlay();
    }

    private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
        @Override
        public void onStartTrackingTouch(SeekBar bar) {
            mDragging = true;
            show(3600000);
            mHandler.removeMessages(SHOW_PROGRESS);
            if (mInstantSeeking)
                mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
            if (mInfoView != null) {
                mInfoView.setText("");
                mInfoView.setVisibility(View.VISIBLE);
            }
        }

        /**
         * 进度条改变回调主要设置进度和时间
         * @param bar
         * @param progress
         * @param fromuser
         */
        @Override
        public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
            if (!fromuser)
                return;

            long newposition = (mDuration * progress) / 1000;
            String time = StringUtils.generateTime(newposition);
            if (mInstantSeeking)
                mPlayer.seekTo(newposition);
            if (mInfoView != null)
                mInfoView.setText(time);
            if (mCurrentTime != null)
                mCurrentTime.setText(time);
        }

        @Override
        public void onStopTrackingTouch(SeekBar bar) {
            if (!mInstantSeeking)
                mPlayer.seekTo((mDuration * bar.getProgress()) / 1000);
            if (mInfoView != null) {
                mInfoView.setText("");
                mInfoView.setVisibility(View.GONE);
            }
            show(sDefaultTimeout);
            mHandler.removeMessages(SHOW_PROGRESS);
            mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
            mDragging = false;
            mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
        }
    };

    @Override
    public void setEnabled(boolean enabled) {
        if (mPauseButton != null)
            mPauseButton.setEnabled(enabled);
        if (mProgress != null)
            mProgress.setEnabled(enabled);
        disableUnsupportedButtons();
        super.setEnabled(enabled);
    }

    /**
     * 控制接口
     */
    public interface MediaPlayerControl {
        void start();

        void pause();

        long getDuration();

        long getCurrentPosition();

        void seekTo(long pos);

        boolean isPlaying();

        int getBufferPercentage();

        boolean canPause();

        boolean canSeekBackward();

        boolean canSeekForward();
    }
}
还有一个自定义TextView是用来显示视频信息的。

/*
 * Copyright (C) 2011 Cedric Fung (wolfplanet@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.videotest.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.TextView;

public class OutlineTextView extends TextView {
   public OutlineTextView(Context context) {
      super(context);
      initPaint();
   }

   public OutlineTextView(Context context, AttributeSet attrs) {
      super(context, attrs);
      initPaint();
   }

   public OutlineTextView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      initPaint();
   }

   private void initPaint() {
      mTextPaint = new TextPaint();
      mTextPaint.setAntiAlias(true);
      mTextPaint.setTextSize(getTextSize());
      mTextPaint.setColor(mColor);
      mTextPaint.setStyle(Paint.Style.FILL);
      mTextPaint.setTypeface(getTypeface());

      mTextPaintOutline = new TextPaint();
      mTextPaintOutline.setAntiAlias(true);
      mTextPaintOutline.setTextSize(getTextSize());
      mTextPaintOutline.setColor(mBorderColor);
      mTextPaintOutline.setStyle(Paint.Style.STROKE);
      mTextPaintOutline.setTypeface(getTypeface());
      mTextPaintOutline.setStrokeWidth(mBorderSize);
   }

   public void setText(String text) {
      super.setText(text);
      mText = text.toString();
      requestLayout();
      invalidate();
   }

   @Override
  public void setTextSize(float size) {
      super.setTextSize(size);
      requestLayout();
      invalidate();
      initPaint();
   }

   @Override
  public void setTextColor(int color) {
      super.setTextColor(color);
      mColor = color;
      invalidate();
      initPaint();
   }

   @Override
  public void setShadowLayer(float radius, float dx, float dy, int color) {
      super.setShadowLayer(radius, dx, dy, color);
      mBorderSize = radius;
      mBorderColor = color;
      requestLayout();
      invalidate();
      initPaint();
   }

   @Override
  public void setTypeface(Typeface tf, int style) {
      super.setTypeface(tf, style);
      requestLayout();
      invalidate();
      initPaint();
   }

   @Override
  public void setTypeface(Typeface tf) {
      super.setTypeface(tf);
      requestLayout();
      invalidate();
      initPaint();
   }

   @Override
   protected void onDraw(Canvas canvas) {
      Layout layout = new StaticLayout(getText(), mTextPaintOutline, getWidth(), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad);
      layout.draw(canvas);
      layout = new StaticLayout(getText(), mTextPaint, getWidth(), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad);
      layout.draw(canvas);
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      Layout layout = new StaticLayout(getText(), mTextPaintOutline, measureWidth(widthMeasureSpec), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad);
      int ex = (int) (mBorderSize * 2 + 1);
      setMeasuredDimension(measureWidth(widthMeasureSpec) + ex, measureHeight(heightMeasureSpec) * layout.getLineCount() + ex);
   }

   private int measureWidth(int measureSpec) {
      int result = 0;
      int specMode = MeasureSpec.getMode(measureSpec);
      int specSize = MeasureSpec.getSize(measureSpec);

      if (specMode == MeasureSpec.EXACTLY) {
         result = specSize;
      } else {
         result = (int) mTextPaintOutline.measureText(mText) + getPaddingLeft() + getPaddingRight();
         if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
         }
      }

      return result;
   }

   private int measureHeight(int measureSpec) {
      int result = 0;
      int specMode = MeasureSpec.getMode(measureSpec);
      int specSize = MeasureSpec.getSize(measureSpec);

      mAscent = (int) mTextPaintOutline.ascent();
      if (specMode == MeasureSpec.EXACTLY) {
         result = specSize;
      } else {
         result = (int) (-mAscent + mTextPaintOutline.descent()) + getPaddingTop() + getPaddingBottom();
         if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
         }
      }
      return result;
   }

   private TextPaint mTextPaint;
   private TextPaint mTextPaintOutline;
   private String mText = "";
   private int mAscent = 0;
   private float mBorderSize;
   private int mBorderColor;
   private int mColor;
   private float mSpacingMult = 1.0f;
   private float mSpacingAdd = 0;
   private boolean mIncludePad = true;
}
由于是用vitamio库来播放视频。因此还得需要一些配置,如下

新建一个包名为

io.vov.vitamio,里面引用资源。

package io.vov.vitamio;

public class R {
   public static final class raw {
      public static final int libarm = com.example.videotest.R.raw.libarm;
      public static final int pub =  com.example.videotest.R.raw.pub;
   }
}
以下是工具类,因为第一次要初始化。
package com.example.videotest.utils;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.WindowManager;

import io.vov.vitamio.Vitamio;


public class InitActivity extends Activity {
   public static final String FROM_ME = "fromVitamioInitActivity";
   public static final String EXTRA_MSG = "EXTRA_MSG";
   public static final String EXTRA_FILE = "EXTRA_FILE";
   private ProgressDialog mPD;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

      new AsyncTask<Object, Object, Object>() {
         @Override
         protected void onPreExecute() {
//          mPD = new ProgressDialog(InitActivity.this);
//          mPD.setCancelable(false);
//          mPD.setMessage(getText(R.string.init_decoders));
//          mPD.show();
         }

         @Override
         protected Object doInBackground(Object... params) {

            Vitamio.initialize(getApplicationContext());
//          if (Vitamio.isInitialized(getApplicationContext()))
//             return null;
//
//          //反射解压
//          try {
//             Class c = Class.forName("io.vov.vitamio.Vitamio");
//             Method extractLibs = c.getDeclaredMethod("extractLibs", new Class[] { android.content.Context.class, int.class });
//             extractLibs.setAccessible(true);
//             extractLibs.invoke(c, new Object[] { getApplicationContext(), R.raw.libarm });
//
               Field vitamioLibraryPath = c.getDeclaredField("vitamioLibraryPath");

                AndroidContextUtils.getDataDir(ctx) + "libs/"
//
//          } catch (NoSuchMethodException e) {
//             Log.e("extractLibs", e);
//             e.printStackTrace();
//          } catch (IllegalArgumentException e) {
//             e.printStackTrace();
//          } catch (IllegalAccessException e) {
//             e.printStackTrace();
//          } catch (InvocationTargetException e) {
//             e.printStackTrace();
//          } catch (ClassNotFoundException e) {
//             e.printStackTrace();
//          }

            uiHandler.sendEmptyMessage(0);
            return null;
         }
      }.execute();
   }

   private Handler uiHandler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
         //mPD.dismiss();
         Intent src = getIntent();
         Intent i = new Intent();
         i.setClassName(src.getStringExtra("package"), src.getStringExtra("className"));
         i.setData(src.getData());
         i.putExtras(src);
         i.putExtra(FROM_ME, true);
         startActivity(i);

         finish();
      }
   };
}
package com.example.videotest.utils;

import android.app.Activity;
import android.content.Intent;

import io.vov.vitamio.Vitamio;

public final class LibsChecker {
   public static final boolean checkVitamioLibs(Activity ctx, int msgID) {
      if ((!Vitamio.isInitialized(ctx)) && (!ctx.getIntent().getBooleanExtra("fromVitamioInitActivity", false))) {
         Intent i = new Intent();
         i.setClassName(ctx.getPackageName(), "com.example.videotest.utils.InitActivity");//io.vov.vitamio.activity.InitActivity
         i.putExtras(ctx.getIntent());
         i.setData(ctx.getIntent().getData());
         i.putExtra("package", ctx.getPackageName());
         i.putExtra("className", ctx.getClass().getName());
         i.putExtra("EXTRA_MSG", msgID);
         ctx.startActivity(i);
         ctx.finish();
         return false;
      }
      return true;
   }
}
接下来是在Activity使用
package com.example.videotest;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;

import com.example.videotest.utils.LibsChecker;
import com.example.videotest.widget.MediaController;
import com.example.videotest.widget.VideoView;

import io.vov.vitamio.MediaPlayer;
import io.vov.vitamio.MediaPlayer.OnCompletionListener;
import io.vov.vitamio.MediaPlayer.OnInfoListener;
public class VideoPlayActivity extends Activity implements OnCompletionListener, OnInfoListener{

   private String mPath;
   private String mTitle;
   private VideoView mVideoView;
   private View mVolumeBrightnessLayout;
   private ImageView mOperationBg;
   private ImageView mOperationPercent;
   private AudioManager mAudioManager;
   /** 最大声音 */
   private int mMaxVolume;
   /** 当前声音 */
   private int mVolume = -1;
   /** 当前亮度 */
   private float mBrightness = -1f;
   /** 当前缩放模式 */
   private int mLayout = VideoView.VIDEO_LAYOUT_ORIGIN;
   private GestureDetector mGestureDetector;
   private MediaController mMediaController;
   private View mLoadingView;
   private ImageView mDefaultImg;
   @Override
   public void onCreate(Bundle bundle) {
      super.onCreate(bundle);

      // ~~~ 检测Vitamio是否解压解码包
      if (!LibsChecker.checkVitamioLibs(this, R.string.init_decoders))
         return;

      // ~~~ 获取播放地址和标题
      Intent intent = getIntent();
      if(null == intent){
         mPath = "http://player.youku.com/player.php/sid/XMTY4MDg2Nzg4MA==/v.swf";
         mTitle = "视频播放";
      }else{
         mPath = intent.getStringExtra("path");
         mTitle = intent.getStringExtra("title");
      }
      
      if (TextUtils.isEmpty(mPath)) {
         //mPath = Environment.getExternalStorageDirectory() + "/video/你太猖狂.flv";
         mPath = "http://video.52xiyou.com/video/FBSP119/baofeng12503.flv";
      } else if (intent.getData() != null)
         mPath = intent.getData().toString();

      // ~~~ 绑定控件
      setContentView(R.layout.vedio_play_activity);
      mVideoView = (VideoView) findViewById(R.id.surface_view);
      mVolumeBrightnessLayout = findViewById(R.id.operation_volume_brightness);
      mOperationBg = (ImageView) findViewById(R.id.operation_bg);
      mOperationPercent = (ImageView) findViewById(R.id.operation_percent);
      mLoadingView = findViewById(R.id.video_loading);

//    View view  = findViewById(R.id.media_player_layout);
//    mVideoView.setView(view);
      // ~~~ 绑定事件
      mVideoView.setOnCompletionListener(this);
      mVideoView.setOnInfoListener(this);

      mDefaultImg = (ImageView) findViewById(R.id.media_player_image);
      // ~~~ 绑定数据
      mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
      mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
      if (mPath.startsWith("http:"))
         mVideoView.setVideoURI(Uri.parse(mPath));
      else
         mVideoView.setVideoPath(mPath);

      //设置显示名称
      mMediaController = new MediaController(this);
      mMediaController.setFileName(mTitle);
      mVideoView.setMediaController(mMediaController);
      mVideoView.requestFocus();

      mGestureDetector = new GestureDetector(this, new MyGestureListener());
      setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
   }

   @Override
   protected void onPause() {
      super.onPause();
      if (mVideoView != null)
         mVideoView.pause();
   }

   @Override
   protected void onResume() {
      super.onResume();
      if (mVideoView != null)
         mVideoView.resume();
   }

   @Override
   protected void onDestroy() {
      super.onDestroy();
      if (mVideoView != null)
         mVideoView.stopPlayback();
   }

   @Override
   public boolean onTouchEvent(MotionEvent event) {
      if (mGestureDetector.onTouchEvent(event))
         return true;

      // 处理手势结束
      switch (event.getAction() & MotionEvent.ACTION_MASK) {
      case MotionEvent.ACTION_UP:
         endGesture();
         break;
      }

      return super.onTouchEvent(event);
   }

   /** 手势结束 */
   private void endGesture() {
      mVolume = -1;
      mBrightness = -1f;

      // 隐藏
      mDismissHandler.removeMessages(0);
      mDismissHandler.sendEmptyMessageDelayed(0, 500);
   }

   private class MyGestureListener extends SimpleOnGestureListener {

      /** 双击 */
      @Override
      public boolean onDoubleTap(MotionEvent e) {
         if (mLayout == VideoView.VIDEO_LAYOUT_ZOOM)
            mLayout = VideoView.VIDEO_LAYOUT_ORIGIN;
         else
            mLayout++;
         if (mVideoView != null)
            mVideoView.setVideoLayout(mLayout, 0);
         return true;
      }

      /** 滑动 */
      @Override
      public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
         float mOldX = e1.getX(), mOldY = e1.getY();
         int y = (int) e2.getRawY();
         Display disp = getWindowManager().getDefaultDisplay();
         int windowWidth = disp.getWidth();
         int windowHeight = disp.getHeight();

         if (mOldX > windowWidth * 4.0 / 5)// 右边滑动
            onVolumeSlide((mOldY - y) / windowHeight);
         else if (mOldX < windowWidth / 5.0)// 左边滑动
            onBrightnessSlide((mOldY - y) / windowHeight);

         return super.onScroll(e1, e2, distanceX, distanceY);
      }
   }

   /** 定时隐藏 */
   private Handler mDismissHandler = new Handler() {
      @Override
      public void handleMessage(Message msg) {
         mVolumeBrightnessLayout.setVisibility(View.GONE);
      }
   };

   /**
    * 滑动改变声音大小
    * 
    * @param percent
    */
   private void onVolumeSlide(float percent) {
      if (mVolume == -1) {
         mVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
         if (mVolume < 0)
            mVolume = 0;

         // 显示
         mOperationBg.setImageResource(R.drawable.video_volumn_bg);
         mVolumeBrightnessLayout.setVisibility(View.VISIBLE);
      }

      int index = (int) (percent * mMaxVolume) + mVolume;
      if (index > mMaxVolume)
         index = mMaxVolume;
      else if (index < 0)
         index = 0;

      // 变更声音
      mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);

      // 变更进度条
      ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams();
      lp.width = findViewById(R.id.operation_full).getLayoutParams().width * index / mMaxVolume;
      mOperationPercent.setLayoutParams(lp);
   }

   /**
    * 滑动改变亮度
    * 
    * @param percent
    */
   private void onBrightnessSlide(float percent) {
      if (mBrightness < 0) {
         mBrightness = getWindow().getAttributes().screenBrightness;
         if (mBrightness <= 0.00f)
            mBrightness = 0.50f;
         if (mBrightness < 0.01f)
            mBrightness = 0.01f;

         // 显示
         mOperationBg.setImageResource(R.drawable.video_brightness_bg);
         mVolumeBrightnessLayout.setVisibility(View.VISIBLE);
      }
      WindowManager.LayoutParams lpa = getWindow().getAttributes();
      lpa.screenBrightness = mBrightness + percent;
      if (lpa.screenBrightness > 1.0f)
         lpa.screenBrightness = 1.0f;
      else if (lpa.screenBrightness < 0.01f)
         lpa.screenBrightness = 0.01f;
      getWindow().setAttributes(lpa);

      ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams();
      lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * lpa.screenBrightness);
      mOperationPercent.setLayoutParams(lp);
   }

   @Override
   public void onConfigurationChanged(Configuration newConfig) {
      if (mVideoView != null)
         mVideoView.setVideoLayout(mLayout, 0);
      super.onConfigurationChanged(newConfig);
   }

   @Override
   public void onCompletion(MediaPlayer player) {
      finish();
   }

   private void stopPlayer() {
      if (mVideoView != null)
         mVideoView.pause();
   }

   private void startPlayer() {
      if (mVideoView != null)
         mVideoView.start();
   }

   private boolean isPlaying() {
      return mVideoView != null && mVideoView.isPlaying();
   }

   /** 是否需要自动恢复播放,用于自动暂停,恢复播放 */
   private boolean needResume;

   @Override
   public boolean onInfo(MediaPlayer arg0, int arg1, int arg2) {
      switch (arg1) {
      case MediaPlayer.MEDIA_INFO_BUFFERING_START:
         //开始缓存,暂停播放
         if (isPlaying()) {
            stopPlayer();
            needResume = true;
         }
         mDefaultImg.setVisibility(View.GONE);
         mLoadingView.setVisibility(View.VISIBLE);
         break;
      case MediaPlayer.MEDIA_INFO_BUFFERING_END:
         //缓存完成,继续播放
         if (needResume)
            startPlayer();
         mLoadingView.setVisibility(View.GONE);
         break;
      case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED:
         //显示 下载速度
         Log.e("","download rate:" + arg2);
         //mListener.onDownloadRateChanged(arg2);
         break;
      }
      return true;
   }
}
接下来是xml布局
controller
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="680dp"
    android:layout_height="74dip"
    android:layout_marginBottom="0.0dip"
    android:layout_marginLeft="0.0dip"
    android:layout_marginRight="0.0dip"
    android:layout_alignParentBottom="true"
    android:layout_gravity="center_horizontal"
    android:background="@drawable/mediacontroller_bg"
    android:orientation="horizontal" >
     <!-- android:layout_alignParentBottom="true" -->
   <!--  android:layout_gravity="center"  -->

    <ImageButton
        android:id="@+id/mediacontroller_play_pause"
        android:layout_width="54.6dip"
        android:layout_height="32dip"
        android:layout_alignParentRight="true"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="7.0dip"
        android:background="#00000000"
        android:contentDescription="@string/mediacontroller_play_pause"
        android:gravity="center"
        android:src="@drawable/mediacontroller_pause_button" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="2dip"
        android:layout_marginLeft="7.0dip"
        android:layout_marginRight="7.0dip"
        android:layout_marginTop="2dip"
        android:layout_toLeftOf="@+id/mediacontroller_play_pause" >

        <RelativeLayout
            android:layout_width="680dp"
            android:layout_height="wrap_content" >

            <TextView
                android:id="@+id/mediacontroller_time_current"
                style="@style/MediaController_Text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentTop="true" />

            <TextView
                android:id="@+id/mediacontroller_time_total"
                style="@style/MediaController_Text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_alignParentTop="true" />
        </RelativeLayout>

        <SeekBar
            android:id="@+id/mediacontroller_seekbar"
            style="@style/MediaController_SeekBar"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:focusable="true"
            android:max="1000" />

        <TextView
            android:id="@+id/mediacontroller_file_name"
            style="@style/MediaController_Text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:ellipsize="marquee"
            android:singleLine="true" />
    </RelativeLayout>

</RelativeLayout>

activity

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="680dp"
    android:layout_height="wrap_content"
    android:layout_gravity="center" >

    <RelativeLayout
        android:id="@+id/media_player_layout"
        android:layout_width="680dp"
        android:layout_height="561dp"
        android:layout_alignParentTop="true"
        android:background="@drawable/media_player_bg" >

        <com.example.videotest.widget.VideoView
            android:id="@+id/surface_view"
            android:layout_width="626dp"
            android:layout_height="470dp"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="20dp" />

        <ImageView
            android:id="@+id/media_player_image"
            android:layout_width="626dp"
            android:layout_height="470dp"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="20dp"
            android:background="@drawable/ic_launcher" />
        <!--
           <include 
               android:id="@+id/Controller"
               layout="@layout/mediacontroller"
               android:layout_alignParentBottom="true"/>
        -->
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/video_loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_vertical"
        android:orientation="horizontal" >

        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="7.0dip"
            android:text="@string/video_layout_loading"
            android:textColor="#ffffff"
            android:textSize="20.0sp" />
    </LinearLayout>

    <FrameLayout
        android:id="@+id/operation_volume_brightness"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="#00000000"
        android:orientation="horizontal"
        android:padding="0dip"
        android:visibility="invisible" >

        <ImageView
            android:id="@+id/operation_bg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@drawable/video_volumn_bg" />

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|center_horizontal"
            android:paddingBottom="25dip" >

            <ImageView
                android:id="@+id/operation_full"
                android:layout_width="94dip"
                android:layout_height="wrap_content"
                android:layout_gravity="left"
                android:src="@drawable/video_num_bg" />

            <ImageView
                android:id="@+id/operation_percent"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:layout_gravity="left"
                android:scaleType="matrix"
                android:src="@drawable/video_num_front" />
        </FrameLayout>
    </FrameLayout>

</RelativeLayout>
manifast文件做如下配置


<activity
    android:name="com.example.videotest.VideoPlayActivity"
    android:configChanges="orientation|keyboard|keyboardHidden|navigation"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.Translucent.NoTitleBar">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <!--  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"  -->
    <!-- android:theme="@android:style/Theme.Translucent.NoTitleBar"  -->
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data
            android:mimeType="audio/*"
            android:scheme="http" />
        <data
            android:mimeType="audio/*"
            android:scheme="rtsp" />
        <data
            android:mimeType="audio/*"
            android:scheme="rtmp" />
        <data
            android:mimeType="audio/*"
            android:scheme="udp" />
        <data
            android:mimeType="audio/*"
            android:scheme="tcp" />
        <data
            android:mimeType="audio/*"
            android:scheme="file" />
        <data
            android:mimeType="audio/*"
            android:scheme="content" />
        <data
            android:mimeType="audio/*"
            android:scheme="mms" />
        <data
            android:mimeType="video/*"
            android:scheme="http" />
        <data
            android:mimeType="video/*"
            android:scheme="rtsp" />
        <data
            android:mimeType="video/*"
            android:scheme="rtmp" />
        <data
            android:mimeType="video/*"
            android:scheme="udp" />
        <data
            android:mimeType="video/*"
            android:scheme="tcp" />
        <data
            android:mimeType="video/*"
            android:scheme="file" />
        <data
            android:mimeType="video/*"
            android:scheme="content" />
        <data
            android:mimeType="video/*"
            android:scheme="mms" />
        <data android:mimeType="application/octet-stream" />
        <data android:mimeType="application/x-mpegurl" />
        <data android:mimeType="application/vnd.apple.mpegurl" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />

        <data android:scheme="content" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data
            android:mimeType="application/x-mpegurl"
            android:scheme="http" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="rtsp" />
        <data android:scheme="rtmp" />
        <data android:scheme="mms" />
        <data android:scheme="tcp" />
        <data android:scheme="udp" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <action android:name="android.intent.action.SEND" />
        <action android:name="android.intent.action.SENDTO" />

        <category android:name="android.intent.category.DEFAULT" />

        <data android:mimeType="video/*" />
        <data android:mimeType="application/sdp" />
        <data android:mimeType="application/octet-stream" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="http" />
        <data android:mimeType="video/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="file" />
        <data android:scheme="content" />
        <data android:scheme="http" />
        <data android:scheme="https" />
        <data android:scheme="ftp" />
        <data android:scheme="rtsp" />
        <data android:scheme="rtmp" />
        <data android:scheme="mms" />
        <data android:scheme="tcp" />
        <data android:scheme="udp" />
        <data android:scheme="gopher" />
        <data android:mimeType="video/*" />
        <data android:mimeType="audio/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="file" />
        <data android:scheme="content" />
        <data android:scheme="http" />
        <data android:scheme="https" />
        <data android:scheme="ftp" />
        <data android:scheme="rtsp" />
        <data android:scheme="rtmp" />
        <data android:scheme="mms" />
        <data android:scheme="tcp" />
        <data android:scheme="udp" />
        <data android:scheme="gopher" />
        <data android:host="*" />
        <data android:pathPattern=".*\\.avi" />
        <data android:pathPattern=".*\\.asf" />
        <data android:pathPattern=".*\\.f4v" />
        <data android:pathPattern=".*\\.flv" />
        <data android:pathPattern=".*\\.mkv" />
        <data android:pathPattern=".*\\.mpeg" />
        <data android:pathPattern=".*\\.mpg" />
        <data android:pathPattern=".*\\.mov" />
        <data android:pathPattern=".*\\.rm" />
        <data android:pathPattern=".*\\.vob" />
        <data android:pathPattern=".*\\.wmv" />
        <data android:pathPattern=".*\\.ts" />
        <data android:pathPattern=".*\\.tp" />
        <data android:pathPattern=".*\\.m3u" />
        <data android:pathPattern=".*\\.m3u8" />
        <data android:pathPattern=".*\\.m4v" />
        <data android:pathPattern=".*\\.mp4" />
        <data android:pathPattern=".*\\.swf" />
        <data android:pathPattern=".*\\.rmvb" />
    </intent-filter>
</activity>
配置支持哪些视频。

完整的demo不知道怎么上传,到时候上传,贴上下载地址。

运行截图:


视频大小大家可以控制,我这里就直接全屏了。

感谢大家阅读。

下载地址:点击打开链接


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值