Android VideoView类实例讲解
本节使用系统的示例类VideoView继续SurfaceView类相关内容的讲解,以让大家能更深入理解Android系统中图形绘制基础类的实现原理。也许你会发现无法改变VideoView类的控制方面,我们可以通过重构VideoView类来实现更加个性化的播放器。
下面是VideoView类的相关代码。
Java代码
publicclassVideoViewextendsSurfaceViewimplementsMediaPlayerControl{ privateStringTAG="VideoView"; //settablebytheclient privateUrimUri; privateintmDuration; //allpossibleinternalstates privatestaticfinalintSTATE_ERROR=-1; privatestaticfinalintSTATE_IDLE=0; privatestaticfinalintSTATE_PREPARING=1; privatestaticfinalintSTATE_PREPARED=2; privatestaticfinalintSTATE_PLAYING=3; privatestaticfinalintSTATE_PAUSED=4; privatestaticfinalintSTATE_PLAYBACK_COMPLETED=5; //mCurrentStateisaVideoViewobject'scurrentstate. //mTargetStateisthestatethatamethodcallerintendstoreach. //Forinstance,regardlesstheVideoViewobject'scurrentstate, //callingpause()intendstobringtheobjecttoatargetstate //ofSTATE_PAUSED. privateintmCurrentState=STATE_IDLE; privateintmTargetState=STATE_IDLE; //Allthestuffweneedforplayingandshowingavideo privateSurfaceHoldermSurfaceHolder=null; privateMediaPlayermMediaPlayer=null; privateintmVideoWidth; privateintmVideoHeight; privateintmSurfaceWidth; privateintmSurfaceHeight; privateMediaControllermMediaController; privateOnCompletionListenermOnCompletionListener; privateMediaPlayer.OnPreparedListenermOnPreparedListener; privateintmCurrentBufferPercentage; privateOnErrorListenermOnErrorListener; privateintmSeekWhenPrepared;//recordingtheseekpositionwhilepreparing privatebooleanmCanPause; privatebooleanmCanSeekBack; privatebooleanmCanSeekForward; publicVideoView(Contextcontext){ super(context); initVideoView(); } publicVideoView(Contextcontext,AttributeSetattrs){ this(context,attrs,0); initVideoView(); } publicVideoView(Contextcontext,AttributeSetattrs,intdefStyle){ super(context,attrs,defStyle); initVideoView(); } @Override protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){ //Log.i("@@@@","onMeasure"); intwidth=getDefaultSize(mVideoWidth,widthMeasureSpec); intheight=getDefaultSize(mVideoHeight,heightMeasureSpec); if(mVideoWidth>0&&mVideoHeight>0){ if(mVideoWidth*height>width*mVideoHeight){ //Log.i("@@@","imagetootall,correcting"); height=width*mVideoHeight/mVideoWidth; }elseif(mVideoWidth*height<width*mVideoHeight){ //Log.i("@@@","imagetoowide,correcting"); width=height*mVideoWidth/mVideoHeight; }else{ //Log.i("@@@","aspectratioiscorrect:"+ //width+"/"+height+"="+ //mVideoWidth+"/"+mVideoHeight); } } //Log.i("@@@@@@@@@@","settingsize:"+width+'x'+height); setMeasuredDimension(width,height); } publicintresolveAdjustedSize(intdesiredSize,intmeasureSpec){ intresult=desiredSize; intspecMode=MeasureSpec.getMode(measureSpec); intspecSize=MeasureSpec.getSize(measureSpec); switch(specMode){ caseMeasureSpec.UNSPECIFIED: result=desiredSize; break; caseMeasureSpec.AT_MOST: /*Parentsayswecanbeasbigaswewant,uptospecSize. *Don'tbelargerthanspecSize,anddon'tbelargerthan *themaxsizeimposedonourselves. */ result=Math.min(desiredSize,specSize); break; caseMeasureSpec.EXACTLY: //Nochoice.Dowhatwearetold. result=specSize; break; } returnresult; } privatevoidinitVideoView(){ 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; } publicvoidsetVideoPath(Stringpath){ setVideoURI(Uri.parse(path)); } publicvoidsetVideoURI(Uriuri){ mUri=uri; mSeekWhenPrepared=0; openVideo(); requestLayout(); invalidate(); } publicvoidstopPlayback(){ if(mMediaPlayer!=null){ mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer=null; mCurrentState=STATE_IDLE; mTargetState=STATE_IDLE; } } privatevoidopenVideo(){ if(mUri==null||mSurfaceHolder==null){ //notreadyforplaybackjustyet,willtryagainlater return; } //Tellthemusicplaybackservicetopause //TODO:theseconstantsneedtobepublishedsomewhereintheframework. Intenti=newIntent("com.android.music.musicservicecommand"); i.putExtra("command","pause"); mContext.sendBroadcast(i); //weshouldn'tclearthetargetstate,becausesomebodymighthave //calledstart()previously release(false); try{ mMediaPlayer=newMediaPlayer(); 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(); //wedon'tsetthetargetstatehereeither,butpreservethe //targetstatethatwastherebefore. mCurrentState=STATE_PREPARING; attachMediaController(); }catch(IOExceptionex){ Log.w(TAG,"Unabletoopencontent:"+mUri,ex); mCurrentState=STATE_ERROR; mTargetState=STATE_ERROR; mErrorListener.onError(mMediaPlayer,MediaPlayer.MEDIA_ERROR_UNKNOWN,0); return; }catch(IllegalArgumentExceptionex){ Log.w(TAG,"Unabletoopencontent:"+mUri,ex); mCurrentState=STATE_ERROR; mTargetState=STATE_ERROR; mErrorListener.onError(mMediaPlayer,MediaPlayer.MEDIA_ERROR_UNKNOWN,0); return; } } publicvoidsetMediaController(MediaControllercontroller){ if(mMediaController!=null){ mMediaController.hide(); } mMediaController=controller; attachMediaController(); } privatevoidattachMediaController(){ if(mMediaPlayer!=null&&mMediaController!=null){ mMediaController.setMediaPlayer(this); ViewanchorView=this.getParent()instanceofView? (View)this.getParent():this; mMediaController.setAnchorView(anchorView); mMediaController.setEnabled(isInPlaybackState()); } } MediaPlayer.OnVideoSizeChangedListenermSizeChangedListener= newMediaPlayer.OnVideoSizeChangedListener(){ publicvoidonVideoSizeChanged(MediaPlayermp,intwidth,intheight){ mVideoWidth=mp.getVideoWidth(); mVideoHeight=mp.getVideoHeight(); if(mVideoWidth!=0&&mVideoHeight!=0){ getHolder().setFixedSize(mVideoWidth,mVideoHeight); } } }; MediaPlayer.OnPreparedListenermPreparedListener=newMediaPlayer.OnPreparedListener(){ publicvoidonPrepared(MediaPlayermp){ mCurrentState=STATE_PREPARED; //Getthecapabilitiesoftheplayerforthisstream Metadatadata=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(); intseekToPosition=mSeekWhenPrepared;//mSeekWhenPreparedmaybechangedafterseekTo()call if(seekToPosition!=0){ seekTo(seekToPosition); } if(mVideoWidth!=0&&mVideoHeight!=0){ //Log.i("@@@@","videosize:"+mVideoWidth+"/"+mVideoHeight); getHolder().setFixedSize(mVideoWidth,mVideoHeight); if(mSurfaceWidth==mVideoWidth&&mSurfaceHeight==mVideoHeight){ //Wedidn'tactuallychangethesize(itwasalreadyatthesize //weneed),sowewon'tgeta"surfacechanged"callback,so //startthevideohereinsteadofinthecallback. if(mTargetState==STATE_PLAYING){ start(); if(mMediaController!=null){ mMediaController.show(); } }elseif(!isPlaying()&& (seekToPosition!=0||getCurrentPosition()>0)){ if(mMediaController!=null){ //Showthemediacontrolswhenwe'repausedintoavideoandmake'emstick. mMediaController.show(0); } } } }else{ //Wedon'tknowthevideosizeyet,butshouldstartanyway. //Thevideosizemightbereportedtouslater. if(mTargetState==STATE_PLAYING){ start(); } } } }; privateMediaPlayer.OnCompletionListenermCompletionListener= newMediaPlayer.OnCompletionListener(){ publicvoidonCompletion(MediaPlayermp){ mCurrentState=STATE_PLAYBACK_COMPLETED; mTargetState=STATE_PLAYBACK_COMPLETED; if(mMediaController!=null){ mMediaController.hide(); } if(mOnCompletionListener!=null){ mOnCompletionListener.onCompletion(mMediaPlayer); } } }; privateMediaPlayer.OnErrorListenermErrorListener= newMediaPlayer.OnErrorListener(){ publicbooleanonError(MediaPlayermp,intframework_err,intimpl_err){ Log.d(TAG,"Error:"+framework_err+","+impl_err); mCurrentState=STATE_ERROR; mTargetState=STATE_ERROR; if(mMediaController!=null){ mMediaController.hide(); } /*Ifanerrorhandlerhasbeensupplied,useitandfinish.*/ if(mOnErrorListener!=null){ if(mOnErrorListener.onError(mMediaPlayer,framework_err,impl_err)){ returntrue; } } /*Otherwise,popupanerrordialogsotheuserknowsthat *somethingbadhashappened.Onlytryandpopupthedialog *ifwe'reattachedtoawindow.Whenwe'regoingawayandno *longerhaveawindow,don'tbothershowingtheuseranerror. */ if(getWindowToken()!=null){ Resourcesr=mContext.getResources(); intmessageId; 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; } newAlertDialog.Builder(mContext) .setTitle(com.android.internal.R.string.VideoView_error_title) .setMessage(messageId) .setPositiveButton(com.android.internal.R.string.VideoView_error_button, newDialogInterface.OnClickListener(){ publicvoidonClick(DialogInterfacedialog,intwhichButton){ /*Ifwegethere,thereisnoonErrorlistener,so *atleastinformthemthatthevideoisover. */ if(mOnCompletionListener!=null){ mOnCompletionListener.onCompletion(mMediaPlayer); } } }) .setCancelable(false) .show(); } returntrue; } }; privateMediaPlayer.OnBufferingUpdateListenermBufferingUpdateListener= newMediaPlayer.OnBufferingUpdateListener(){ publicvoidonBufferingUpdate(MediaPlayermp,intpercent){ mCurrentBufferPercentage=percent; } }; /** *Registeracallbacktobeinvokedwhenthemediafile *isloadedandreadytogo. * *@paramlThecallbackthatwillberun */ publicvoidsetOnPreparedListener(MediaPlayer.OnPreparedListenerl) { mOnPreparedListener=l; } /** *Registeracallbacktobeinvokedwhentheendofamediafile *hasbeenreachedduringplayback. * *@paramlThecallbackthatwillberun */ publicvoidsetOnCompletionListener(OnCompletionListenerl) { mOnCompletionListener=l; } /** *Registeracallbacktobeinvokedwhenanerroroccurs *duringplaybackorsetup.Ifnolistenerisspecified, *orifthelistenerreturnedfalse,VideoViewwillinform *theuserofanyerrors. * *@paramlThecallbackthatwillberun */ publicvoidsetOnErrorListener(OnErrorListenerl) { mOnErrorListener=l; } SurfaceHolder.CallbackmSHCallback=newSurfaceHolder.Callback() { publicvoidsurfaceChanged(SurfaceHolderholder,intformat, intw,inth) { mSurfaceWidth=w; mSurfaceHeight=h; booleanisValidState=(mTargetState==STATE_PLAYING); booleanhasValidSize=(mVideoWidth==w&&mVideoHeight==h); if(mMediaPlayer!=null&&isValidState&&hasValidSize){ if(mSeekWhenPrepared!=0){ seekTo(mSeekWhenPrepared); } start(); if(mMediaController!=null){ mMediaController.show(); } } } publicvoidsurfaceCreated(SurfaceHolderholder) { mSurfaceHolder=holder; openVideo(); } publicvoidsurfaceDestroyed(SurfaceHolderholder) { //afterwereturnfromthiswecan'tusethesurfaceanymore mSurfaceHolder=null; if(mMediaController!=null)mMediaController.hide(); release(true); } }; privatevoidrelease(booleancleartargetstate){ if(mMediaPlayer!=null){ mMediaPlayer.reset(); mMediaPlayer.release(); mMediaPlayer=null; mCurrentState=STATE_IDLE; if(cleartargetstate){ mTargetState=STATE_IDLE; } } } @Override publicbooleanonTouchEvent(MotionEventev){ if(isInPlaybackState()&&mMediaController!=null){ toggleMediaControlsVisiblity(); } returnfalse; } @Override publicbooleanonTrackballEvent(MotionEventev){ if(isInPlaybackState()&&mMediaController!=null){ toggleMediaControlsVisiblity(); } returnfalse; } @Override publicbooleanonKeyDown(intkeyCode,KeyEventevent) { booleanisKeyCodeSupported=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(); } returntrue; }elseif(keyCode==KeyEvent.KEYCODE_MEDIA_STOP &&mMediaPlayer.isPlaying()){ pause(); mMediaController.show(); }else{ toggleMediaControlsVisiblity(); } } returnsuper.onKeyDown(keyCode,event); } privatevoidtoggleMediaControlsVisiblity(){ if(mMediaController.isShowing()){ mMediaController.hide(); }else{ mMediaController.show(); } } publicvoidstart(){ if(isInPlaybackState()){ mMediaPlayer.start(); mCurrentState=STATE_PLAYING; } mTargetState=STATE_PLAYING; } publicvoidpause(){ if(isInPlaybackState()){ if(mMediaPlayer.isPlaying()){ mMediaPlayer.pause(); mCurrentState=STATE_PAUSED; } } mTargetState=STATE_PAUSED; } //cachedurationasmDurationforfasteraccess publicintgetDuration(){ if(isInPlaybackState()){ if(mDuration>0){ returnmDuration; } mDuration=mMediaPlayer.getDuration(); returnmDuration; } mDuration=-1; returnmDuration; } publicintgetCurrentPosition(){ if(isInPlaybackState()){ returnmMediaPlayer.getCurrentPosition(); } return0; } publicvoidseekTo(intmsec){ if(isInPlaybackState()){ mMediaPlayer.seekTo(msec); mSeekWhenPrepared=0; }else{ mSeekWhenPrepared=msec; } } publicbooleanisPlaying(){ returnisInPlaybackState()&&mMediaPlayer.isPlaying(); } publicintgetBufferPercentage(){ if(mMediaPlayer!=null){ returnmCurrentBufferPercentage; } return0; } privatebooleanisInPlaybackState(){ return(mMediaPlayer!=null&& mCurrentState!=STATE_ERROR&& mCurrentState!=STATE_IDLE&& mCurrentState!=STATE_PREPARING); } publicbooleancanPause(){ returnmCanPause; } publicbooleancanSeekBackward(){ returnmCanSeekBack; } publicbooleancanSeekForward(){ returnmCanSeekForward; } }
以上就是对AndroidVideoView类的详细介绍,后续继续补充相关知识,谢谢大家对本站的支持!