文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android VideoView类实例讲解

2022-06-06 07:50

关注

        本节使用系统的示例类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: 
     
    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 (mOnErrorListener != null) { 
    if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) { 
     return true; 
    } 
   } 
    
   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 (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; 
  } 
 }; 
  
 public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) 
 { 
  mOnPreparedListener = l; 
 } 
  
 public void setOnCompletionListener(OnCompletionListener l) 
 { 
  mOnCompletionListener = l; 
 } 
  
 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&MediaPlayer)Android videoview抢占焦点的处理方法android之视频播放系统VideoView和自定义VideoView控件的应用Android编程实现VideoView循环播放功能的方法Android多媒体之VideoView视频播放器Android使用VideoView播放本地视频和网络视频的方法详解Android App中使用VideoView来实现视频播放的方法Android自定义播放器控件VideoViewandroid使用videoview播放视频android多媒体类VideoView使用方法详解


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯