Android -- 多媒体播放之MediaPlayer基础简介

本文详细介绍了Android中的MediaPlayer类,包括其状态转换、有效方法调用、内部实现原理等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android -- MediaPlayer基础简介


MediaPlayer是Android中的一个多媒体播放类,我们能通过它控制音视频流或本地音视频资源的播放过程。

这段时间查阅了Android官方文档对MediaPlayer的介绍,同时也看了一些书籍介绍。现在把MediaPlayer的基础内容在此做一个记录,以供后面查阅、回忆。


MediaPlayer系统的主要代码实现介绍如下:


1、Java部分

MediaPlayer.java

Java类主要的路径在\frameworks\base\media\java\android\media\MediaPlayer.java

2、Native部分

MediaPlayer.java中的功能实现都借助JNI调到Native层,JNI主要实现在\frameworks\base\media\jni\android_media_MediaPlayer.cpp,这部分编译会得到libmedia_jni.so库。
多媒体底层库的代码实现主要在\frameworks\av\media\libmedia\目录下,这部分编译得到的是libmedia.so库。
最后多媒体服务部分的代码实现主要在\frameworks\av\media\libmediaplayerservice\目录下,这部分编译得到的是libmediaplayerservice.so库。

这三个库的调用关系如图所示:MediaPlayer.java -> libmedia_jni.so -> libmedia.so -> libmediaplayerservice.so.


下图是一个MediaPlayer对象被支持的播放控制操作驱动的声明周期和状态。其中,椭圆代表MediaPlayer可能驻留的状态,弧线表示驱动MediaPlayer在各个状态之间迁移的播放控制操作。这里有两种类型的弧线。由单箭头开始的弧线代表同步方法调用,而以双箭头开头的弧线代表异步方法调用。图片介绍来源于官方文。



通过上图,我们知道一个MediaPlayer对象有如下几种状态。

  1. 当一个MediaPlayer对象被刚刚用new操作符或者是调用了reset()方法后,就处于Idle状态。当调用了release()方法后,处于End状态。这两种状态之间是MediaPlayer对象的生命周期。
     在一个新构建的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()方法,并将错误的状态传入。
当一个MediaPlayer对象不再被使用时,应立即调用release()方法来释放在内部的播放引擎与这个MediaPlayer对象关联的资源。资源可能包括硬件加速组件的单态固件,若没有调用release()方法可能会导致之后的MediaPlayer对象实例无法使用这种单态硬件资源,从而导致程序异常。一旦MediaPlayer对象进入了End状态,将不能再被使用,也没有办法再迁移到其他状态。
此外,使用new操作符创建的MediaPlayer对象处于Idle状态,而那些通过重载的create()方法创建的MediaPlayer对象却不是处于Idle状态。事实上,如果成功调用了重载的create()方法,这些对象就已经是Prepare状态了。
   
    2. 一般情况下,由于种种原因一些播放控制操作可能会失败,如不支持的音频/视频格式、缺少隔行扫描的音频/视频、分辨率太高、流超时等,因此,错误报告和恢复在这种情况下是非常重要的。有时由于编程错误,在处于无效状态的情况下调用了一个播放器控制操作的情况是可能发生的。在所有这些错误条件下,内部播放引擎会调用一个由客户端程序提供的OnErrorListener.onError()方法。客户端程序可以通过调用 setOnErrorListener(android.media.MediaPlayer.OnErrorListener)方法注册OnErrorListener对象。
一旦发生错误,MediaPlayer对象会进入Error状态。为了重用一个处于Error状态的MediaPlayer对象,可以调用reset()方法把这个对象恢复到Idle状态。注册一个OnErrorListener来获知内部播放引擎发生的错误是一个好的编程习惯。在不合法的状态下调用一些方法,如prepare()、prepareAsync()和setDataSource()等会抛出ILlegalStateException异常。

    3. 调用 setDataSource(FileDescriptor), setDataSource(String), setDataSource(Context, Uri), setDataSource(FileDescriptor, long, long)方法会使处于Idle状态的对象迁移到Initialized状态。若当此MediaPlayer对象处于其他状态下,调用setDataSource()方法会抛出 ILlegalStateException异常。时刻注意调用setDataSource()方法可能会抛出的ILlegalStateException异常和IOException异常是一个好的编程习惯。

    4. 在开始播放前,MediaPlayer对象必须要进入Prepared状态。有两种方法可以使MediaPlayer对象进入Prepared状态。
        (1)、调用prepare()方法(同步):此方法返回就表示该MediaPlayer对象已经进入了Prepared状态。
        (2)、调用prepareAsync方法(异步):此方法会使MediaPlayer对象进入Preparing状态并返回,内部的播放引擎会继续未完成的工作。
当同步版本返回或异步版本的准备工作完全完成时就会调用客户端程序提供的OnPrepareListener.onPrepared()监听方法。可以调用方法MediaPlayer.setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener)来注册OnPreparedListener。
Preparing是一个中间状态,如果在此状态下调用任何影响播放功能的方法,最终的运行结果都是未知的。在不合适的状态下调用prepare()和prepareAsync()方法会抛出ILlegalStateException异常。当MediaPlayer对象处于Prepared状态时,可以调整音视频的属性,如音量、播放时是否一致亮屏、循环播放等。

    5. 在要开始播放时必须调用start()方法。当此方法成功返回时,MediaPlayer对象处于Started状态。isPlaying()方法可以被用来测试某个MediaPlayer对象是否处于Started状态。
当处于Started状态时,内部播放引擎会调用客户端程序提供的OnBufferingUpdateListener.onBufferingUpdate()回调方法,此回调方法允许应用程序追踪流播放的缓冲状态。对一个已经处于Started状态的MediaPlayer对象调用start()方法没有影响。

    6. 播放可以被暂停、停止,以及调整播放进度。当调用pause()方法并返回时,会使MediaPlayer对象进入Paused状态。注意Started与Paused状态的相互转换在内部的播放引擎中是异步的,所以可能需要一点时间在isPlaying()方法中更新状态,若在播放流内容,这段时间可能会有几秒钟。
调用start()方法会让一个处于Paused状态的MediaPlayer对象从之前的暂停状态恢复到播放状态。当start()方法返回时,MediaPlayer对象的状态又会变成Started状态。对一个已经处于Paused状态的MediaPlayer对象,调用pause()方法没有任何影响。

    7. 调用stop()方法会停止播放,并且还会让一个处于Started、Paused、Prepared或者PlaybackCompleted状态的MediaPlayer对象进入Stopped状态。对一个已经处于Stopped状态的MediaPlayer对象,调用stop()方法没有影响

    8. 调用seekTo()方法可以调整播放的位置。方法seekTo(int)是异步执行的,所以可以马上返回,但是实际的定位播放操作可能需要一段时间才能完成,尤其是播放流形式的音视频。当实际的定位播放操作完成后,内部的播放引擎会调用客户端程序提供的OnSeekComplete.onSeekComplete()回调方法。可以通过setOnSeekCompleteListener(OnSeekCompleteListener)方法注册。
在此需要注意,seekTo(int)方法也可以在其他状态下调用,例如Prepared、Paused和PlaybackCompleted状态。此外,目前的播放位置,实际可以调用getCurrentPosition()方法得到,可以帮助如音乐播放器之类的应用程序不断更新播放进度。

    9. 当播放到流的末尾时,这次播放操作就彻底完成。如果调用setLooping(boolean)方法开启了循环模式,那么这个MediaPlayer对象就会重新进入到Started状态。如果没有开启循环模式,那么内部的播放引擎会调用客户端程序提供的OnCompletion.onCompletion()回调方法。可以通过调用MediaPlayer.setOnCompletionListener(OnCompletionListener)方法来设置。内部的播放引擎一旦调用了OnCompletion.onCompletion()方法,说明这个MediaPlayer对象进入了PlaybackCompleted状态。当处于PlaybackCompleted状态时,可以调用start()方法来让这个MediaPlayer对象再次进入Started状态。

MediaPlayer方法的有效状态和无效状态
方法

有效状态

无效状态

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 Preparedstate. 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 Preparingstate. 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

{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 Initializedstate. 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.

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.

MediaPlayer中可使用的回调

在播放过程中,应用程序也许会想去注册一些回调函数来获取一些内部状态更新或运行错误的事件信息。所有这些都可以通过正确的设置一些监听对象来实现:

setOnPreparedListener(OnPreparedListener)setOnPreparedListener, 

setOnVideoSizeChangedListener(OnVideoSizeChangedListener)setOnVideoSizeChangedListener,

setOnSeekCompleteListener(OnSeekCompleteListener)setOnSeekCompleteListener, 

setOnCompletionListener(OnCompletionListener)setOnCompletionListener, 

setOnBufferingUpdateListener(OnBufferingUpdateListener)setOnBufferingUpdateListener, 

setOnInfoListener(OnInfoListener)setOnInfoListener, 

setOnErrorListener(OnErrorListener)setOnErrorListener, etc

为了能通过这些监听器正确收到相关联的回调,在创建MediaPlayer对象时,要确保它所在的线程必须有自己的消息循环(Looper)。


MediaPlayer中的内嵌类
interface MediaPlayer.OnBufferingUpdateListener Interface definition of a callback to be invoked indicating buffering status of a media resource being streamed over the network. 
interface MediaPlayer.OnCompletionListener Interface definition for a callback to be invoked when playback of a media source has completed. 
interface MediaPlayer.OnErrorListener Interface definition of a callback to be invoked when there has been an error during an asynchronous operation (other errors will throw exceptions at method call time).  
interface MediaPlayer.OnInfoListener Interface definition of a callback to be invoked to communicate some info and/or warning about the media or its playback. 
interface MediaPlayer.OnPreparedListener Interface definition for a callback to be invoked when the media source is ready for playback. 
interface MediaPlayer.OnSeekCompleteListener Interface definition of a callback to be invoked indicating the completion of a seek operation. 
interface MediaPlayer.OnTimedTextListener Interface definition of a callback to be invoked when a timed text is available for display. 
interface MediaPlayer.OnVideoSizeChangedListener Interface definition of a callback to be invoked when the video size is first known or updated  
class MediaPlayer.TrackInfo Class for MediaPlayer to return each audio/video/subtitle track's metadata. 
                      


PS:以上所有内容都可以到MediaPlayer Android官方文档获取更准确的介绍。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值