Android MediaPlayer

android.media.MediaPlayer

     MediaPlayer 类可以用来控制音频/视频文件的播放, android.widget.VideoView 类演示了如何使用 MediaPlayer 这个类的方法。

本章的主题包括以下几个方面:
1. State Diagram(状态转换图)
2. Valid and Invalid States(有效与无效状态)
3. Permissions(权限)
4. Register informational and error callbacks(注册消息与错误回调)

State Diagram

  音/视频文件的回放及流的播放控制可以用一个状态机来描述。下面的这张图展示了一个 MediaPlayer 对象的生命周期及各种可能的状态,这些状态的转换都是由回放控制操作来完成的。其中的椭圆代表了一个 MediaPlayer 对象可以处于的状态,而那些弧线代表了回放控制操作使对象发生的状态转换。下图有两种类型的弧线,带单个箭头的弧线表示同步(synchronous)方法调用,而带有双箭头的弧线表示异步(asynchronous)方法调用。

Android MediaPlayer_第1张图片
  从这个状态机图中可以看到,一个 MediaPlayer 对象有下面这些状态:

1.     当一个 MediaPlayer 对象刚通过 new 来创建或在调用 reset() 方法被调用后,这个对象就处于 Idle 状态;而在 release() 方法被调用后,该对象就处于 End 状态。MediaPlayer 对象的生命周期就处于这两个状态之间。

(1)一个刚由 new 创建的全新的 MediaPlayer 对象与被调用了 reset() 方法的 MediaPlayer 对象之间有一个微小但是却非常重要的差别。在 Idle 状态下,调用这两种对象的  getCurrentPosition()getDuration()getVideoHeight()getVideoWidth()setAudioStreamType(int),setLooping(boolean)setVolume(float, float)pause()start()stop()seekTo(int)prepare() or  prepareAsync() 方法都是错误的用法。在一个 MediaPlayer 对象刚被创建之后,就马上调用这些方法中的任意一个或多个,那么提供给用户的 OnErrorListener.onError() 回调方法是不会被内部的播放引擎调用的,且对象状态保持不变。但是如果在调用 reset() 方法后,就马上调用这些方法中的一个或多个,OnErrorListener.onError() 回调方法就会被内部的播放引擎调用,且对象会转换到 Error 状态。
(2)当一个 MediaPlayer 对象不再被使用时,建议马上调用 release() 方法,这样 MediaPlayer 对象的相关播放引擎所使用的资源就会立即被释放掉,这些资源可能包括单例资源(如硬件加速组件)。如果调用 release() 方法失败,会导致 MediaPlayer 对象无法正确地回退到相应的状态。一旦一个 MediaPlayer 对象进入 End 状态,它就不可再使用了,也不可能使它转换到其它任何一种状态。
(3)此外,用 new 来创建的 MediaPlayer 对象在创建刚完成时处于 Idle 状态,而那些通过重载的 create() 方法所创建的对象在创建刚完成时是不会处于 Idle 对象的。事实上,如果 create() 方法调用成功,那么这些对象就会处理 Prepared 状态。

2.  通过,一些播放控制操作可能会由于各种原因而失败,如 audio/video 格式不受支持、音/视频交错模式有错、分辨率太高、流超时等。所以在这种情况下,错误报告和恢复就显得非常重要。有时,可能也会由于编程上的失误,在 Invalid 状态下调用播放控制操作。在所有这些错误发生时,如果事先已经通过 setOnErrorListener(android.media.MediaPlayer.OnErrorListener) 方法注册了一个OnErrorListener 对象,那么内部的播放引擎就会调用提供给用户的 OnErrorListener.onError() 方法。

(1)注意当错误发生时,即使 error listener 对象没有被注册,MediaPlayer 对象也会进入 Error 状态(除了上面提到的那种情况之外);
(2)为了重新使用一个处于 Error 状态的 MediaPlayer 对象及从错误中恢复过来,可以通过调用 reset() 方法来使该对象恢复到 Idle 状态;
(3)为了方便查看内部播放引擎所报告的出错情况,建议你要为自己的应用注册 OnErrorListener 监听器;
(4)为了防止编程失误,如在 Invalid 状态调用  prepare()prepareAsync(), 或任意一种重载的  setDataSource 方法,在进行一些非常操作时会抛出  IllegalStateException 错误。

3.   调用  setDataSource(FileDescriptor), or  setDataSource(String), or  setDataSource(Context, Uri), or  setDataSource(FileDescriptor,  long, long) 方法会使一个 MediaPlayer 对象从 Idle 状态转换到 Initialized 状态。

(1)在 Idle 状态之外的其它任一状态下调用 setDataSource() 方法,会抛出一个 IllegalStateException 错误;
(2)建议注意调用 setDataSource() 重载方法时所可能抛出的 IllegalArgumentException 和 IOException 错误。

4.  在播放开始前,一个 MediaPlayer 对象必须先进入 Prepared 状态。

(1)有两种途径(同步、异步)可以进入 Prepared 状态:第一种是通过调用 prepare() (同步)方法,当这个方法返回时,MediaPlayer 对象就进入 Prepared 状态了;第二种方法是通过调用 prepareAsync() (异步)方法,这个方法返回后,内部的播放引擎会继续进行一系列的准备工作,直到这些工作全部完成后,MediaPlayer 对象就进入 Prepared 状态了。紧接着,如果用户事先通过 setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener) 方法注册了一个监听器,那么内部播放引擎就会回调用 OnPrepareListener 接口的 onPrepared() 方法。
(2)注意 Praparing 状态是一个瞬时状态,在 Preparing 状态下调用任何方法可能产生的副作用还没有定义;
(3)在其它任何状态下调用  prepare() or  prepareAsync() 都抛出 IllegalStateException 错误;
(4)在 Prepared 状态下,可以通过相关方法调用来调整 audio/sound volume, screenOnWhilePlaying, looping 等属性。

5.  开始播放一定得由 start() 方法来完成,在 start() 方法成功返回后,MediaPlayer 对象就处于 Started 状态。可以通过调用 isPlaying() 方法来检测 MediaPlayer 对象是否处于 Started 状态。

(1)在 Started 状态下,如果用户事先通过 setOnBufferingUpdateListener(OnBufferingUpdateListener)  方法注册了一个 OnBufferingUpdateListener 监听器,那么内部的播放引擎就会调用它提供给用户的 OnBufferingUpdateListener.onBufferingUpdate() 
回调方法。这个回调方法可实现应用程序对音/视频流缓冲状态的跟踪。
(2)如果一个 MediaPlayer 对象已经处于 Started 状态,那么再调用 stasrt() 方法将不会再起什么作用了。

6.  播放可以暂停或停止,当前播放的位置也可以进行调整。可以通过调用 pause() 来暂停播放,这个方法返回后,MediaPlayer 对象就进入 Paused 状态。注意内部播放引擎进行的从 Started 状态到 Paused 状态的转换是异步的,反之亦然。在调用 isPlaying() 后,状态的更新可能需要花一点时间。

(1)调用 start() 方法可以使 MediaPlayer 对象从 paused 状态恢复到播放状态,播放起始位置就是之前它停止时候的位置,当 start() 方法返回时,MediaPlayer 就回到 Started 状态了;
(2)如果一个 MediaPlayer 已经处于 Paused 状态,那么再调用 pause() 将不会再起什么使用了。

7.  调用 stop() 方法可以停止播放,也可以使一个 MediaPlayer 对象从 Started, Paused, Prepared 或 PlaybackCompleted 进入 Stopped 状态。
(1)一旦进入 Stopped 状态,就无法再开始播放直到再次调用 prepare() 或 prepareAsync() 方法使 MediaPlayer 对象重新进入 Prepared 状态;
(2)如果 MediaPlayer 对象已经处于 Stopped 状态,那么再调用 stop() 方法将不会再起什么使用了。

8.  可以通过 seekTo(int) 方法调整播放位置。
(1)虽然异步的 seekTo(int) 方法会立即返回,但是实际上 seek 操作需要一点时间才可完成,特别是当 audio/video 已经被转换成流了以后。当重定位完成后,如果用户事先已经通过 setOnSeekCompleteListener(OnSeekCompleteListener) 方法注册了一个 OnSeekCompleteListener 对象,那么播放引擎就会回调提供给用户的 OnSeekComplete.onSeekComplete() 方法;
(2)注意在其它状态下,seekTo(int) 方法也可以被调用,如在 Prepared、Paused 和 PlaybackComleted 状态下。
(3)此外,可以通过 getCurrentPosition() 方法来获取当前的播放位置,这对于跟踪当前播放进度是非常有用的。

9.  当播放到流的末尾时,播放就完成了。
(1)如果设置了 looping 模式已经通过 setLooping(boolean)  设置为 true ,那么 MediaPlayer 对象就会保持在 Started 状态(即播放到流的末尾后再重复播放);
(2)如果 looping 模式设置为 false ,那么如果用户事先已经通过 setOnCompletionListener(OnCompletionListener)  方法注册了一个 OnCompletionListener 监听器,那么播放引擎就会回调提供给用户的 OnCompletion.onCompletion() 方法;
(3)在处于 PlaybackCompleted 状态时,如果调用 start() 方法,那么就会重新从 audio/video 源的开始处播放。


Valid and invalid states

  在官方文档中,有一个表格说明了在 Valid 与 Invalid 状态下,可以调用及不可调用的方法,在出错时请留意,在此省略......

Permissions

如果你需要声明相关的 WAKE_LOCK ,那请在配置文件中通过 <uses-permission> 元素来定义;
如果你要在 MediaPlayer 类中使用网络资源,请在配置文件中申请 android.Manifest.permission.INTERNET 权限。

Callbacks

  如果应用程序需要对内部状态的更新或在播放时出错的信息进行监听捕获,那么就可以通过注册适当的监听器来实现,下面是一些常用的注册监听器的方法

via calls to 

 setOnPreparedListener(OnPreparedListener)setOnPreparedListener,

  setOnVideoSizeChangedListener(OnVideoSizeChangedListener)setOnVideoSizeChangedListener, 

  setOnSeekCompleteListener(OnSeekCompleteListener)setOnSeekCompleteListener, 

  setOnCompletionListener(OnCompletionListener)setOnCompletionListener, 

  setOnBufferingUpdateListener(OnBufferingUpdateListener)setOnBufferingUpdateListener, 

  setOnInfoListener(OnInfoListener)setOnInfoListener,

  setOnErrorListener(OnErrorListener)setOnErrorListener, etc).

  In order to receive the respective callback associated with these listeners, applications are required to create MediaPlayer objects on a thread with its own Looper running (main UI thread by default has a Looper running).



--------下面是这个类的内部接口(类)、 常量方法等具体内容--------


Nested Classes(内部类)
interface
MediaPlayer.OnBufferingUpdateListener 定义了当从网络上接收 media source 时的缓冲状态的回调
interface
MediaPlayer.OnCompletionListener 定义了当 media source 播放完成时的回调
interface
MediaPlayer.OnErrorListener 定义了当进行异步操作出错时的回调(其它错误将会在方法调用时就抛出)
interface
MediaPlayer.OnInfoListener 定义了一些通信信息和媒体播放过程中出现警告时的回调
interface
MediaPlayer.OnPreparedListener 当 media source 准备好播放时回调
interface
MediaPlayer.OnSeekCompleteListener 当 seek 操作完成时的回调
interface
MediaPlayer.OnTimedTextListener 当一个定时的文本可用于显示时的回调
interface
MediaPlayer.OnVideoSizeChangedListener 当 video size 第一次被知道或更新时的回调
class
MediaPlayer.TrackInfo 一个用于给 MediaPlayer 返回每个 audio/video/subtitle track's 的元信息的类



  这个常量表的用处非常大,当程序出错时,在 Log 里会打印出相应的错误信息。在这些信息中,每个 Constant Value: 701 (0x000002bd) 形式的信息对应一个具体的常理,所以你可以根据这个表知道程序出了什么错。
Constants(常量)
int MEDIA_ERROR_IO 文件或网络相关操作出错
int MEDIA_ERROR_MALFORMED Bitstream 与相关的编码标准或具体文件不相匹配
int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK video 已经被转换成流且其容器不支持 progressive 播放,如 video 的下标没有从文件的开始处算起
int MEDIA_ERROR_SERVER_DIED Media server 挂掉了
int MEDIA_ERROR_TIMED_OUT 一些操作长时间没完成(超时),通常是3-5秒
int MEDIA_ERROR_UNKNOWN 一些未定义的 media 播放器错误
int MEDIA_ERROR_UNSUPPORTED Bitstream 与相关的编码标准相符合,但是 media 框架并不支持其特性要求
int MEDIA_INFO_BAD_INTERLEAVING 交错出错意味着交错存储的 media 有错误或者根本没交错
int MEDIA_INFO_BUFFERING_END MediaPlayer is resuming playback after filling buffers.
int MEDIA_INFO_BUFFERING_START 为了缓冲更多的数据,MediaPlayer 暂停播放
int MEDIA_INFO_METADATA_UPDATE 一个新的元数据集可用
int MEDIA_INFO_NOT_SEEKABLE media 无法定位播放(如直播)
int MEDIA_INFO_SUBTITLE_TIMED_OUT 读取字幕 track 超时
int MEDIA_INFO_UNKNOWN 未定义的 media player 信息
int MEDIA_INFO_UNSUPPORTED_SUBTITLE media framework 不支持 subtitle track
int MEDIA_INFO_VIDEO_RENDERING_START The player just pushed the very first video frame for rendering.
int MEDIA_INFO_VIDEO_TRACK_LAGGING video 太复杂,以致于 decoder 无法解码,即 decode 帧的速度太慢
String MEDIA_MIMETYPE_TEXT_SUBRIP MIME type for SubRip (SRT) container.
int VIDEO_SCALING_MODE_SCALE_TO_FIT Specifies a video scaling mode.
int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING Specifies a video scaling mode.

Public Constructors
 
MediaPlayer()
默认的构造方法

Public Methods(公有方法)
void
addTimedTextSource(Context context, Uri uri, String mimeType)
Adds an external timed text source file (Uri).增加一个外部的 timed text 源文件(Uri)
void
addTimedTextSource(String path, String mimeType)
增加一个外部的 timed text 源文件
void
addTimedTextSource(FileDescriptor fd, long offset, long length, String mimeType)
增加一个外部的 timed text 源文件 (FileDescriptor).
void
addTimedTextSource(FileDescriptor fd, String mimeType)
增加一个外部的 timed text 源文件(FileDescriptor).
void
attachAuxEffect(int effectId)
Attaches an auxiliary effect to the player.
static MediaPlayer
create(Context context, Uri uri, SurfaceHolder holder)
为指定的 Uri 创建一个 MediaPlayer 对象
static MediaPlayer
create(Context context, int resid)
为指定的 resource id 创建一个MediaPlayer 对象
static MediaPlayer
create(Context context, Uri uri)
为指定的 Uri 创建一个 MediaPlayer 对象
void
deselectTrack(int index)
取消一个 track
int
getAudioSessionId()
返回 audio session 的 ID
int
getCurrentPosition()
返回当前播放的位置
int
getDuration()
返回 file 的时长
TrackInfo[]
getTrackInfo()
通过一个数组返回一个 track 的信息
int
getVideoHeight()
Returns the height of the video.
int
getVideoWidth()
Returns the width of the video.
boolean
isLooping()
Checks whether the MediaPlayer is looping or non-looping.
boolean
isPlaying()
Checks whether the MediaPlayer is playing.
void
pause()
Pauses playback.
void
prepare()
Prepares the player for playback, synchronously.
void
prepareAsync()
Prepares the player for playback, asynchronously.
void
release()
Releases resources associated with this MediaPlayer object.
void
reset()
Resets the MediaPlayer to its uninitialized state.
void
seekTo(int msec)
Seeks to specified time position.
void
selectTrack(int index)
Selects a track.
void
setAudioSessionId(int sessionId)
Sets the audio session ID.
void
setAudioStreamType(int streamtype)
Sets the audio stream type for this MediaPlayer.
void
setAuxEffectSendLevel(float level)
Sets the send level of the player to the attached auxiliary effect .
void
setDataSource(String path)
Sets the data source (file-path or http/rtsp URL) to use.
void
setDataSource(Context context, Uri uri, Map<String, String> headers)
Sets the data source as a content Uri.
void
setDataSource(Context context, Uri uri)
Sets the data source as a content Uri.
void
setDataSource(FileDescriptor fd, long offset, long length)
Sets the data source (FileDescriptor) to use.
void
setDataSource(FileDescriptor fd)
Sets the data source (FileDescriptor) to use.
void
setDisplay(SurfaceHolder sh)
Sets the  SurfaceHolder to use for displaying the video portion of the media.
void
setLooping(boolean looping)
Sets the player to be looping or non-looping.
void
setNextMediaPlayer(MediaPlayer next)
Set the MediaPlayer to start when this MediaPlayer finishes playback (i.e.
void
setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener)
Register a callback to be invoked when the status of a network stream's buffer has changed.
void
setOnCompletionListener(MediaPlayer.OnCompletionListener listener)
Register a callback to be invoked when the end of a media source has been reached during playback.
void
setOnErrorListener(MediaPlayer.OnErrorListener listener)
Register a callback to be invoked when an error has happened during an asynchronous operation.
void
setOnInfoListener(MediaPlayer.OnInfoListener listener)
Register a callback to be invoked when an info/warning is available.
void
setOnPreparedListener(MediaPlayer.OnPreparedListener listener)
Register a callback to be invoked when the media source is ready for playback.
void
setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener)
Register a callback to be invoked when a seek operation has been completed.
void
setOnTimedTextListener(MediaPlayer.OnTimedTextListener listener)
Register a callback to be invoked when a timed text is available for display.
void
setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener)
Register a callback to be invoked when the video size is known or updated.
void
setScreenOnWhilePlaying(boolean screenOn)
Control whether we should use the attached SurfaceHolder to keep the screen on while video playback is occurring.
void
setSurface(Surface surface)
Sets the  Surface to be used as the sink for the video portion of the media.
void
setVideoScalingMode(int mode)
Sets video scaling mode.
void
setVolume(float leftVolume, float rightVolume)
设置播放声音
void
setWakeMode(Context context, int mode)
Set the low-level power management behavior for this MediaPlayer.
void
start()
开始或恢复播放
void
stop()
停止播放

Protected Methods(保护方法)
void
finalize()
当垃圾回收器发现某个对象不可达时,调用此方法以回收该对象的内存




你可能感兴趣的:(android,媒体,mediaplayer,状态转换)