Android VideoView类实例讲解_Android

        本节使用系统的示例类VideoView继续SurfaceView类相关内容的讲解,以让大家能更深入理解Android系统中图形绘制基础类的实现原理。也许你会发现无法改变VideoView类的控制方面,我们可以通过重构VideoView类来实现更加个性化的播放器。

         下面是VideoView类的相关代码。

Java 代码

 public class VideoView extends SurfaceView implements MediaPlayerControl {
 private String TAG = "VideoView";
 // settable by the client
 private Uri   mUri;
 private int   mDuration; 

 // all possible internal states
 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; 

 // mCurrentState is a VideoView object's current state.
 // mTargetState is the state that a method caller intends to reach.
 // For instance, regardless the VideoView object's current state,
 // calling pause() intends to bring the object to a target state
 // of STATE_PAUSED.
 private int mCurrentState = STATE_IDLE;
 private int mTargetState = STATE_IDLE; 

 // All the stuff we need for playing and showing a video
 private SurfaceHolder mSurfaceHolder = null;
 private MediaPlayer mMediaPlayer = null;
 private int   mVideoWidth;
 private int   mVideoHeight;
 private int   mSurfaceWidth;
 private int   mSurfaceHeight;
 private MediaController mMediaController;
 private OnCompletionListener mOnCompletionListener;
 private MediaPlayer.OnPreparedListener mOnPreparedListener;
 private int   mCurrentBufferPercentage;
 private OnErrorListener mOnErrorListener;
 private int   mSeekWhenPrepared; // recording the seek position while preparing
 private boolean  mCanPause;
 private boolean  mCanSeekBack;
 private boolean  mCanSeekForward; 

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

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

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

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  //Log.i("@@@@", "onMeasure");
  int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
  int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
  if (mVideoWidth > 0 && mVideoHeight > 0) {
   if ( mVideoWidth * height > width * mVideoHeight ) {
    //Log.i("@@@", "image too tall, correcting");
    height = width * mVideoHeight / mVideoWidth;
   } else if ( mVideoWidth * height < width * mVideoHeight ) {
    //Log.i("@@@", "image too wide, correcting");
    width = height * mVideoWidth / mVideoHeight;
   } else {
    //Log.i("@@@", "aspect ratio is correct: " +
      //width+"/"+height+"="+
      //mVideoWidth+"/"+mVideoHeight);
   }
  }
  //Log.i("@@@@@@@@@@", "setting size: " + width + 'x' + height);
  setMeasuredDimension(width, height);
 } 

 public int resolveAdjustedSize(int desiredSize, int measureSpec) {
  int result = desiredSize;
  int specMode = MeasureSpec.getMode(measureSpec);
  int specSize = MeasureSpec.getSize(measureSpec); 

  switch (specMode) {
   case MeasureSpec.UNSPECIFIED:
        result = desiredSize;
    break; 

   case MeasureSpec.AT_MOST:
    /* Parent says we can be as big as we want, up to specSize.
     * Don't be larger than specSize, and don't be larger than
     * the max size imposed on ourselves.
     */
    result = Math.min(desiredSize, specSize);
    break; 

   case MeasureSpec.EXACTLY:
    // No choice. Do what we are told.
    result = specSize;
    break;
  }
  return result;
} 

 private void initVideoView() {
  mVideoWidth = 0;
  mVideoHeight = 0;
  getHolder().addCallback(mSHCallback);
  getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  setFocusable(true);
  setFocusableInTouchMode(true);
  requestFocus();
  mCurrentState = STATE_IDLE;
  mTargetState = STATE_IDLE;
 } 

 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) {
   // not ready for playback just yet, will try again later
   return;
  }
  // Tell the music playback service to pause
  // TODO: these constants need to be published somewhere in the framework.
  Intent i = new Intent("com.android.music.musicservicecommand");
  i.putExtra("command", "pause");
  mContext.sendBroadcast(i); 

  // we shouldn't clear the target state, because somebody might have
  // called start() previously
  release(false);
  try {
   mMediaPlayer = new MediaPlayer();
   mMediaPlayer.setOnPreparedListener(mPreparedListener);
   mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
   mDuration = -1;
   mMediaPlayer.setOnCompletionListener(mCompletionListener);
   mMediaPlayer.setOnErrorListener(mErrorListener);
   mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
   mCurrentBufferPercentage = 0;
   mMediaPlayer.setDataSource(mContext, mUri);
   mMediaPlayer.setDisplay(mSurfaceHolder);
   mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
   mMediaPlayer.setScreenOnWhilePlaying(true);
   mMediaPlayer.prepareAsync();
   // we don't set the target state here either, but preserve the
   // target state that was there before.
   mCurrentState = STATE_PREPARING;
   attachMediaController();
  } catch (IOException ex) {
   Log.w(TAG, "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.w(TAG, "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();
 } 

 private void attachMediaController() {
  if (mMediaPlayer != null && mMediaController != null) {
   mMediaController.setMediaPlayer(this);
   View anchorView = this.getParent() instanceof View ?
     (View)this.getParent() : this;
   mMediaController.setAnchorView(anchorView);
   mMediaController.setEnabled(isInPlaybackState());
  }
 } 

 MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
  new MediaPlayer.OnVideoSizeChangedListener() {
   public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
    mVideoWidth = mp.getVideoWidth();
    mVideoHeight = mp.getVideoHeight();
    if (mVideoWidth != 0 && mVideoHeight != 0) {
     getHolder().setFixedSize(mVideoWidth, mVideoHeight);
    }
   }
 }; 

 MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
  public void onPrepared(MediaPlayer mp) {
   mCurrentState = STATE_PREPARED; 

   // Get the capabilities of the player for this stream
   Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,
          MediaPlayer.BYPASS_METADATA_FILTER); 

   if (data != null) {
    mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)
      || data.getBoolean(Metadata.PAUSE_AVAILABLE);
    mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)
      || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);
    mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)
      || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);
   } else {
    mCanPause = mCanSeekForward = mCanSeekForward = true;
   } 

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

   int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
   if (seekToPosition != 0) {
    seekTo(seekToPosition);
   }
   if (mVideoWidth != 0 && mVideoHeight != 0) {
    //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
    getHolder().setFixedSize(mVideoWidth, mVideoHeight);
    if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
     // We didn't actually change the size (it was already at the size
     // we need), so we won't get a "surface changed" callback, so
     // start the video here instead of in the callback.
     if (mTargetState == STATE_PLAYING) {
      start();
      if (mMediaController != null) {
       mMediaController.show();
      }
     } else if (!isPlaying() &&
        (seekToPosition != 0 || getCurrentPosition() > 0)) {
      if (mMediaController != null) {
       // Show the media controls when we're paused into a video and make 'em stick.
       mMediaController.show(0);
      }
     }
    }
   } else {
    // We don't know the video size yet, but should start anyway.
    // The video size might be reported to us later.
    if (mTargetState == STATE_PLAYING) {
     start();
    }
   }
  }
 }; 

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

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

   /* If an error handler has been supplied, use it and finish. */
   if (mOnErrorListener != null) {
    if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
     return true;
    }
   } 

   /* Otherwise, pop up an error dialog so the user knows that
    * something bad has happened. Only try and pop up the dialog
    * if we're attached to a window. When we're going away and no
    * longer have a window, don't bother showing the user an error.
    */
   if (getWindowToken() != null) {
    Resources r = mContext.getResources();
    int messageId; 

    if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
     messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback;
    } else {
     messageId = com.android.internal.R.string.VideoView_error_text_unknown;
    } 

    new AlertDialog.Builder(mContext)
      .setTitle(com.android.internal.R.string.VideoView_error_title)
      .setMessage(messageId)
      .setPositiveButton(com.android.internal.R.string.VideoView_error_button,
        new DialogInterface.OnClickListener() {
         public void onClick(DialogInterface dialog, int whichButton) {
          /* If we get here, there is no onError listener, so
           * at least inform them that the video is over.
           */
          if (mOnCompletionListener != null) {
           mOnCompletionListener.onCompletion(mMediaPlayer);
          }
         }
        })
      .setCancelable(false)
      .show();
   }
   return true;
  }
 }; 

 private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
  new MediaPlayer.OnBufferingUpdateListener() {
  public void onBufferingUpdate(MediaPlayer mp, int percent) {
   mCurrentBufferPercentage = percent;
  }
 }; 

 /**
  * Register a callback to be invoked when the media file
  * is loaded and ready to go.
  *
  * @param l The callback that will be run
  */
 public void setOnPreparedListener(MediaPlayer.OnPreparedListener l)
 {
  mOnPreparedListener = l;
 } 

 /**
  * Register a callback to be invoked when the end of a media file
  * has been reached during playback.
  *
  * @param l The callback that will be run
  */
 public void setOnCompletionListener(OnCompletionListener l)
 {
  mOnCompletionListener = l;
 } 

 /**
  * Register a callback to be invoked when an error occurs
  * during playback or setup. If no listener is specified,
  * or if the listener returned false, VideoView will inform
  * the user of any errors.
  *
  * @param l The callback that will be run
  */
 public void setOnErrorListener(OnErrorListener l)
 {
  mOnErrorListener = l;
 } 

 SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
 {
  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) {
     mMediaController.show();
    }
   }
  } 

  public void surfaceCreated(SurfaceHolder holder)
  {
   mSurfaceHolder = holder;
   openVideo();
  } 

  public void surfaceDestroyed(SurfaceHolder holder)
  {
   // after we return from this we can't use the surface any more
   mSurfaceHolder = null;
   if (mMediaController != null) mMediaController.hide();
   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) {
    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();
  }
 } 

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

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

 // cache duration as mDuration for faster access
 public int getDuration() {
  if (isInPlaybackState()) {
   if (mDuration > 0) {
    return mDuration;
   }
   mDuration = mMediaPlayer.getDuration();
   return mDuration;
  }
  mDuration = -1;
  return mDuration;
 } 

 public int getCurrentPosition() {
  if (isInPlaybackState()) {
   return mMediaPlayer.getCurrentPosition();
  }
  return 0;
 } 

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

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

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

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

 public boolean canPause() {
  return mCanPause;
 } 

 public boolean canSeekBackward() {
  return mCanSeekBack;
 } 

 public boolean canSeekForward() {
  return mCanSeekForward;
 }
} 

       以上就是对Android VideoView 类的详细介绍,后续继续补充相关知识,谢谢大家对本站的支持!

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
, videoview
, VideoView类
VideoView类详解
android videoview、android视频videoview、ijkvideoview android、android开发videoview、android videoview 闪,以便于您获取更多的相关知识。

时间: 2024-09-16 20:15:04

Android VideoView类实例讲解_Android的相关文章

Android VideoView类实例讲解

本节使用系统的示例类VideoView继续SurfaceView类相关内容的讲解,以让大家能更深入理解Android系统中图形绘制基础类的实现原理.也许你会发现无法改变VideoView类的控制方面,我们可以通过重构VideoView类来实现更加个性化的播放器. 下面是VideoView类的相关代码. Java 代码 public class VideoView extends SurfaceView implements MediaPlayerControl { private String

Android自定义控件LinearLayout实例讲解_Android

很多时候Android常用的控件不能满足我们的需求,那么我们就需要自定义一个控件了.今天做了一个自定义控件的实例,来分享下. 首先定义一个layout实现按钮内部布局:  <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width=

Android:下拉刷新+加载更多+滑动删除实例讲解_Android

         小伙伴们在逛淘宝或者是各种app上,都可以看到这样的功能,下拉刷新和加载更多以及滑动删除,刷新,指刷洗之后使之变新,比喻突破旧的而创造出新的,比如在手机上浏览新闻的时候,使用下拉刷新的功能,我们可以第一时间掌握最新消息,加载更多是什么nie,简单来说就是在网页上逛淘宝的时候,我们可以点击下一页来满足我们更多的需求,但是在手机端就不一样了,没有上下页,怎么办nie,方法总比困难多,细心的小伙伴可能会发现,在手机端中,有加载更多来满足我们的要求,其实加载更多也是分页的一种体现.小伙

Android 常见的四种对话框实例讲解_Android

1.对话框通知(Dialog Notification) 当你的应用需要显示一个进度条或需要用户对信息进行确认时,可以使用对话框来完成. 下面代码将打开一个如图所示的对话框: public void click1(View view) { AlertDialog.Builder builder = new Builder(this); builder.setTitle("工学1号馆"); builder.setIcon(R.drawable.ic_launcher); builder.

Android 对话框 Dialog使用实例讲解_Android

对话框 Dialog 什么是对话框 对话框是在当前的页面之上弹出的小窗口, 用于显示一些重要的提示信息, 提示用户的输入,确认信息,或显示某种状态.如 : 显示进度条对话框, 退出提示. 对话框的特点: 1, 当前界面弹出的小窗口. 2, 用户要与它进行交互, 可以接收用户输入的信息, 也可以反馈信息给用户. 常用对话框: 1, 普通对话框 AlertDialog 2, 进度条对话框 ProgressDialog 3, 日期对话框 DatePickerDialog 4, 时间对话框 TimePi

Android Studio应用开发集成百度语音合成使用方法实例讲解_Android

首先,语音合成是指将文本信息转换成声音.意思就是将文本转化为声音,让你的应用开口说话.国内在业内比较有名的第三方语音合成平台有百度语音和科大讯飞. 本文集成的是百度语音合成,其主要特点是: 完全永久免费 业界首创完全永久免费新形式,为开发者提供最流畅最自然的语音合成服务.完全免费,永久使用,彻底摆脱限制. 离线在线融合模式 SDK可以根据当前网络状况,自动判断使用本地引擎还是云端引擎进行语音合成,再也不用担心流量消耗! 多语言多音色可选 中文普通话.中英文混读.男声.女声任你选,更支持语速.音调

Android 蓝牙开发实例解析_Android

在使用手机时,蓝牙通信给我们带来很多方便.那么在Android手机中怎样进行蓝牙开发呢?本文以实例的方式讲解Android蓝牙开发的知识.        1.使用蓝牙的响应权限 XML/HTML代码 <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN&qu

Android RecyclerView 数据绑定实例代码_Android

前言 在上一个项目里有很多很多很多很多的RecyclerView,然后我需要写很多很多很多很多的Adapter和Viewholder--多倒没问题,但是里面有很多重复的代码这就不能忍了!每一个Adapter和ViewHolder其实做的事情非常的像:视图绑定,数据绑定,点击事件分发.还有啥?既然它们做的事情都一样,为啥我们还要傻傻的继续写着重复的代码? 正文 BaseAdapter 通常我们要创建一个RecyclerView.Adapter是怎么做的? 接收一个数据列表 重写getItemCou

Android计时器chronometer使用实例讲解_Android

在Android中,可以使用计时器来实现对时间的监测,这个类所实现的功能有开始计时,停止计时,重新计时,设置计 时模式,下面列出计时器方法的原型:long getBase();//返回基地的时间,由setBase(long)设置的String getFormat(); //返回当前字符串格式,此格式是通过setFormat()实现的void setBase(long base); //设置时间,计数定时器指定的值void setFormat(String format); //设置显示的内容,计