Android 原生 MediaPlayer 和 MediaCodec 的区别和联系(二)
目录:
(3)Android 官方网站 对 MediaPlayer的介绍
正文:
MediaPlayer
public class MediaPlayer
MediaPlayer类被用来控制音/视频文件和流的播放。可以在VideoView中找到有关如何使用此类中的方法的示例。
这里涉及的主题是:
1. 状态图
2. 有效和无效状态
3. 权限
4. 注册信息和错误回调
★ 开发者指南
有关如何使用MediaPlayer的更多信息,请阅读Media Playback开发人员指南。
状态图
音/视频文件和流的播放控制是作为一个状态机来进行管理。下图显示了受支持的播放控制操作驱动的MediaPlayer对象的生命周期和状态。 椭圆表示MediaPlayer对象可能驻留的状态。弧表示驱动对象状态转换的播放控制操作。有两种类型的弧。 单箭头的弧表示同步方法调用,而双箭头的弧表示异步方法调用。
从这个状态图中,可以看到MediaPlayer对象具有以下状态:
- 当使用 new 创建MediaPlayer对象或者在调用 reset() 之后,它处于空闲状态; 并且在调用 release() 之后,它处于 End 状态。 在这两个状态之间是MediaPlayer对象的生命周期。
1. 一个新构造的 MediaPlayer 对象 和 调用 reset() 方法后的MediaPlayer对象之间存在微妙但重要的区别。针对这两种情况的空闲状态下调用诸如 getCurrentPosition(), getDuration(), getVideoHeight(),getVideoWidth(),setAudioAttributes(AudioAttributes), setLooping(boolean),setVolume(float, float),pause(), start(), stop(), seekTo(long, int), prepare() or prepareAsync() 方法是程序设计错误。如果在一个 MediaPlayer 对象被构造后任意调用这些方法,则内部播放引擎不会调用用户提供的回调方法OnErrorListener.onError(),并且该对象状态保持不变;但是如果这些方法是在reset()后被调用,则内部播放引擎将调用用户提供的回调方法OnErrorListener.onError(),并且该对象将被转换为 Error 状态。
2. 还建议一旦不再使用MediaPlayer对象,立即调用release(),以便可以立即释放与MediaPlayer对象关联的内部播放器引擎使用的资源。 资源可能包括单一资源(如硬件加速组件)和调用release()失败可能导致MediaPlayer对象的后续实例回退到软件实现或完全失败(?)。 一旦MediaPlayer对象处于End状态,就无法再使用它,也无法将其恢复到任何其他状态。
3. 此外,使用new创建的MediaPlayer对象处于空闲状态,而使用其中一个重载的方便的创建方法创建的对象不处于空闲状态。 实际上,如果使用create方法创建成功,则对象处于Prepared状态。
- 通常,一些播放控制操作可能由于各种原因而失败,例如不支持的音频/视频格式,交错的音频/视频,分辨率太高,流超时等。因此,在这些情况下,关注错误报告和恢复是非常重要的。有时,由于编程错误,也可能在无效状态下调用播放控制操作。在所有这些错误条件下,如果开发者事先通过setOnErrorListener(android.media.MediaPlayer.OnErrorListener)注册了 OnErrorListener ,则内部播放器引擎会调用开发者提供的 OnErrorListener.onError() 方法。
1. 重要的是要注意,一旦发生错误,MediaPlayer对象就会进入错误状态(Error state)(除非如上所述),即使应用程序尚未注册错误监听器也是如此。
3. 让应用程序注册OnErrorListener以查找内部播放器引擎的错误通知是一种很好的编程习惯。
4. 调用譬如 prepare(),prepareAsync()时,或者一个在无效状态(Idle state)重写的 setDataSource 方法时,抛出IllegalStateException 可以防止编程错误。
- 调用 setDataSource(FileDescriptor), 或 setDataSource(String), 或 setDataSource(Context, Uri), 或 setDataSource(FileDescriptor, long, long), 或 setDataSource(MediaDataSource)
将一个 MediaPlayer 对象从空闲状态(Idle state) 转换为 初始状态(Initialized state)。
1. 如果在任何其他状态下调用 setDataSource() ,则抛出 IllegalStateException。
2. 关注从重载的 setDataSource 方法 可能会抛出 IllegalArgumentException 和 IOException 是一种很好的编程习惯。
- 在开始播放之前,MediaPlayer 对象必须先进入准备状态。
1. 有两种方法(同步与异步)可以达到Prepared状态(Prepared state):调用prepare()(同步),一旦方法调用返回就将对象转换为Prepared状态(Prepared state),或者调用prepareAsync()( 异步),它在调用返回后首先将对象转换为Preparation状态(Preparing state)(几乎正确地发生),同时内部播放器引擎继续处理其余的准备工作,直到准备工作完成。 当准备完成或者prepare() 调用返回时,如果事先通过setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener)注册了OnPreparedListener,则内部播放器引擎会调用开发者提供的OnPreparedListener接口的回调方法onPrepared()。
2. 重要的是要注意,准备状态是暂时状态,并且在MediaPlayer对象处于准备状态时调用任何具有副作用的方法的行为是未定义的。
3. 在任何其他状态调用 prepare() 或 prepareAsync() ,则抛出 IllegalStateException。
4. 在Prepared状态(Prepared state)下,可以通过调用相应的set方法来调整音频/音量,screenOnWhilePlaying,循环等属性。
- 要开始播放,必须调用 start() ,start() 返回成功后,MediaPlayer对象则处于 Started状态(Started state)。isPlaying()可用来测试 MediaPlayer对象是否处于 Started状态(Started state)。
1. 处于Started状态(Started state)时,如果事先通过 setOnBufferingUpdateListener(OnBufferingUpdateListener)注册了OnBufferingUpdateListener,则内部播放器引擎会调用用户提供的.OnBufferingUpdateListener.onBufferingUpdate() 回调方法。 此回调允许应用程序在流式传输音频/视频时跟踪缓冲状态。
2. 调用 start() 对已处于Started状态的MediaPlayer对象没有影响。
- 播放可以暂停和停止,并可以调整当前播放位置。 可以通过pause()暂停播放。 当对pause()的调用返回时,MediaPlayer对象进入Paused状态(Pausedstate)。 请注意,从“已启动”状态(Started state)到“暂停”状态(Paused state)的转换(反之亦然)在播放器引擎中异步发生。 在调用isPlaying()时更新状态可能需要一些时间,对于流内容,它可能需要几秒钟。
1. 调用start()以恢复暂停的MediaPlayer对象的播放,并且恢复的播放位置与暂停的位置相同。 当对start()的调用返回时,暂停的MediaPlayer对象将返回到Started状态(Started state)。
2. 调用pause()对已处于Paused状态的MediaPlayer对象没有影响。
- 调用stop()会停止播放并导致处于Started,Paused,Prepared或PlaybackCompleted状态(state)的MediaPlayer进入Stopped状态(Stopped state)。
1. 一旦处于Stopped状态(Stopped state),在调用prepare()或prepareAsync()以将MediaPlayer对象再次设置为Prepared状态(Prepared state)之前,无法启动播放。
2. 调用stop()对已处于Stopped状态(Stopped state)的MediaPlayer对象没有影响。
- 可以通过调用seekTo(long, int)调整播放位置
1. 尽管异步seekTo(long, int)调用立即返回,但实际的寻位操作可能需要一段时间才能完成,特别是对于流式传输的音频/视频。 当实际寻位操作完成时,如果事先通过setOnSeekCompleteListener(OnSeekCompleteListener)注册了OnSeekCompleteListener,则内部播放器引擎会调用开发者提供的OnSeekComplete.onSeekComplete() 。
2. 请注意,seekTo(long, int)也可以在其他状态中调用,例如Prepared,Paused和PlaybackCompleted状态(state)。 当在这些状态中调用seekTo(long, int)时,如果流具有视频且请求的位置有效,则将显示一个视频帧。
3. 此外,可以通过调用getCurrentPosition()来检索实际当前播放位置,这对于需要跟踪播放进度的音乐播放器等应用程序很有帮助。
- 当播放到达流的结尾时,播放完成。
1. 如果使用setLooping(boolean)将循环模式设置为true,则MediaPlayer对象应保持为Started状态(Started state)。
2. 如果循环模式设置为false,则播放器引擎调用开发者提供的回调方法OnCompletion.onCompletion(),如果事先通过 setOnCompletionListener(OnCompletionListener)注册了OnCompletionListener。 调用回调信号表示对象现在处于PlaybackCompleted状态(PlaybackCompleted state)。
3. 在PlaybackCompleted状态(PlaybackCompleted state)下,调用start()可以从音频/视频源的开头重新开始播放。
有效和无效状态
Method Name | Valid Sates | Invalid States | Comments |
attachAuxEffect | {Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} | {Idle, Error} | This method must be called after setDataSource. Calling it does not change the object state. |
getAudioSessionId | any | {} | This method can be called in any state and calling it does not change the object state. |
getCurrentPosition | {Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} | {Error} | Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state. |
getDuration | {Prepared, Started, Paused, Stopped, PlaybackCompleted} | {Idle, Initialized, Error} | Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state. |
getVideoHeight | {Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} | {Error} | Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state. |
getVideoWidth | {Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} | {Error} | Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state. |
isPlaying | {Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} | {Error} | Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state. |
pause | {Started, Paused, PlaybackCompleted} | {Idle, Initialized, Prepared, Stopped, Error} | Successful invoke of this method in a valid state transfers the object to the Paused state. Calling this method in an invalid state transfers the object to the Error state. |
prepare | {Initialized, Stopped} | {Idle, Prepared, Started, Paused, PlaybackCompleted, Error} | Successful invoke of this method in a valid state transfers the object to the Prepared state. Calling this method in an invalid state throws an IllegalStateException. |
prepareAsync | {Initialized, Stopped} | {Idle, Prepared, Started, Paused, PlaybackCompleted, Error} | Successful invoke of this method in a valid state transfers the object to the Preparing state. Calling this method in an invalid state throws an IllegalStateException. |
release | any | {} | After release(), the object is no longer available. |
reset | {Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, Error} | {} | After reset(), the object is like being just created. |
seekTo | {Prepared, Started, Paused, PlaybackCompleted} | {Idle, Initialized, Stopped, Error} | Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state. |
setAudioAttributes | {Idle, Initialized, Stopped, Prepared, Started, Paused, PlaybackCompleted} | {Error} | Successful invoke of this method does not change the state. In order for the target audio attributes type to become effective, this method must be called before prepare() or prepareAsync(). |
setAudioSessionId | {Idle} | {Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, Error} | This method must be called in idle state as the audio session ID must be known before calling setDataSource. Calling it does not change the object state. |
setAudioStreamType (deprecated) | {Idle, Initialized, Stopped, Prepared, Started, Paused, PlaybackCompleted} | {Error} | Successful invoke of this method does not change the state. In order for the target audio stream type to become effective, this method must be called before prepare() or prepareAsync(). |
setAuxEffectSendLevel | any | {} | Calling this method does not change the object state. |
setDataSource | {Idle} | {Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, Error} | Successful invoke of this method in a valid state transfers the object to the Initialized state. Calling this method in an invalid state throws an IllegalStateException. |
setDisplay | any | {} | This method can be called in any state and calling it does not change the object state. |
setSurface | any | {} | This method can be called in any state and calling it does not change the object state. |
setVideoScalingMode | {Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} | {Idle, Error} | Successful invoke of this method does not change the state. |
setLooping | {Idle, Initialized, Stopped, Prepared, Started, Paused, PlaybackCompleted} | {Error} | Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state. |
isLooping | any | {} | This method can be called in any state and calling it does not change the object state. |
setOnBufferingUpdateListener | any | {} | This method can be called in any state and calling it does not change the object state. |
setOnCompletionListener | any | {} | This method can be called in any state and calling it does not change the object state. |
setOnErrorListener | any | {} | This method can be called in any state and calling it does not change the object state. |
setOnPreparedListener | any | {} | This method can be called in any state and calling it does not change the object state. |
setOnSeekCompleteListener | any | {} | This method can be called in any state and calling it does not change the object state. |
setPlaybackParams | {Initialized, Prepared, Started, Paused, PlaybackCompleted, Error} | {Idle, Stopped} | This method will change state in some cases, depending on when it's called. |
setScreenOnWhilePlaying | any | {} | This method can be called in any state and calling it does not change the object state. |
setVolume | {Idle, Initialized, Stopped, Prepared, Started, Paused, PlaybackCompleted} | {Error} | Successful invoke of this method does not change the state. |
setWakeMode | any | {} | This method can be called in any state and calling it does not change the object state. |
start | {Prepared, Started, Paused, PlaybackCompleted} | {Idle, Initialized, Stopped, Error} | Successful invoke of this method in a valid state transfers the object to the Started state. Calling this method in an invalid state transfers the object to the Error state. |
stop | {Prepared, Started, Stopped, Paused, PlaybackCompleted} | {Idle, Initialized, Error} | Successful invoke of this method in a valid state transfers the object to the Stopped state. Calling this method in an invalid state transfers the object to the Error state. |
getTrackInfo | {Prepared, Started, Stopped, Paused, PlaybackCompleted} | {Idle, Initialized, Error} | Successful invoke of this method does not change the state. |
addTimedTextSource | {Prepared, Started, Stopped, Paused, PlaybackCompleted} | {Idle, Initialized, Error} | Successful invoke of this method does not change the state. |
selectTrack | {Prepared, Started, Stopped, Paused, PlaybackCompleted} | {Idle, Initialized, Error} | Successful invoke of this method does not change the state. |
deselectTrack | {Prepared, Started, Stopped, Paused, PlaybackCompleted} | {Idle, Initialized, Error} | Successful invoke of this method does not change the state. |
权限
可能需要声明相应的WAKE_LOCK权限<uses-permission>元素。
当使用网络内容时该类要求声明 Manifest.permission.INTERNET 权限。
回调
应用程序可能希望注册信息和错误事件,以便在播放或流式传输期间获知某些内部状态更新和可能的运行时错误。注册这些事件是由正确设置相应的监听器(通过调用setOnPreparedListener(OnPreparedListener) setOnPreparedListener,setOnVideoSizeChangedListener(OnVideoSizeChangedListener) setOnVideoSizeChangedListener,setOnSeekCompleteListener(OnSeekCompleteListener)setOnSeekCompleteListener,setOnCompletionListener(OnCompletionListener) setOnCompletionListener,setOnBufferingUpdateListener(OnBufferingUpdateListener) setOnBufferingUpdateListener,setOnInfoListener(OnInfoListener) setOnInfoListener,setOnErrorListener(OnErrorListener) setOnErrorListener等完成)。 为了接收与这些侦听器关联的相应回调,应用程序需要在运行自己的Looper线程上创建MediaPlayer对象(默认情况下,主UI线程正在运行Looper)。