Android -- 多媒体播放之MediaPlayer基础简介_mediaplayer 占native吗-程序员宅基地

技术标签: Android音视频框架分析  音视频  Android播放器  Binder机制  mediaplayer  Android  

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官方文档获取更准确的介绍。



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/csdn_of_coder/article/details/63684353

智能推荐

解决win10/win8/8.1 64位操作系统MT65xx preloader线刷驱动无法安装_mt65驱动-程序员宅基地

文章浏览阅读1.3w次。转载自 http://www.miui.com/thread-2003672-1-1.html 当手机在刷错包或者误修改删除系统文件后会出现无法开机或者是移动定制(联通合约机)版想刷标准版,这时就会用到线刷,首先就是安装线刷驱动。 在XP和win7上线刷是比较方便的,用那个驱动自动安装版,直接就可以安装好,完成线刷。不过现在也有好多机友换成了win8/8.1系统,再使用这个_mt65驱动

SonarQube简介及客户端集成_sonar的客户端区别-程序员宅基地

文章浏览阅读1k次。SonarQube是一个代码质量管理平台,可以扫描监测代码并给出质量评价及修改建议,通过插件机制支持25+中开发语言,可以很容易与gradle\maven\jenkins等工具进行集成,是非常流行的代码质量管控平台。通CheckStyle、findbugs等工具定位不同,SonarQube定位于平台,有完善的管理机制及强大的管理页面,并通过插件支持checkstyle及findbugs等既有的流..._sonar的客户端区别

元学习系列(六):神经图灵机详细分析_神经图灵机方法改进-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏27次。神经图灵机是LSTM、GRU的改进版本,本质上依然包含一个外部记忆结构、可对记忆进行读写操作,主要针对读写操作进行了改进,或者说提出了一种新的读写操作思路。神经图灵机之所以叫这个名字是因为它通过深度学习模型模拟了图灵机,但是我觉得如果先去介绍图灵机的概念,就会搞得很混乱,所以这里主要从神经图灵机改进了LSTM的哪些方面入手进行讲解,同时,由于模型的结构比较复杂,为了让思路更清晰,这次也会分开几..._神经图灵机方法改进

【机器学习】机器学习模型迭代方法(Python)-程序员宅基地

文章浏览阅读2.8k次。一、模型迭代方法机器学习模型在实际应用的场景,通常要根据新增的数据下进行模型的迭代,常见的模型迭代方法有以下几种:1、全量数据重新训练一个模型,直接合并历史训练数据与新增的数据,模型直接离线学习全量数据,学习得到一个全新的模型。优缺点:这也是实际最为常见的模型迭代方式,通常模型效果也是最好的,但这样模型迭代比较耗时,资源耗费比较多,实时性较差,特别是在大数据场景更为困难;2、模型融合的方法,将旧模..._模型迭代

base64图片打成Zip包上传,以及服务端解压的简单实现_base64可以装换zip吗-程序员宅基地

文章浏览阅读2.3k次。1、前言上传图片一般采用异步上传的方式,但是异步上传带来不好的地方,就如果图片有改变或者删除,图片服务器端就会造成浪费。所以有时候就会和参数同步提交。笔者喜欢base64图片一起上传,但是图片过多时就会出现数据丢失等异常。因为tomcat的post请求默认是2M的长度限制。2、解决办法有两种:① 修改tomcat的servel.xml的配置文件,设置 maxPostSize=..._base64可以装换zip吗

Opencv自然场景文本识别系统(源码&教程)_opencv自然场景实时识别文字-程序员宅基地

文章浏览阅读1k次,点赞17次,收藏22次。Opencv自然场景文本识别系统(源码&教程)_opencv自然场景实时识别文字

随便推点

ESXi 快速复制虚拟机脚本_exsi6.7快速克隆centos-程序员宅基地

文章浏览阅读1.3k次。拷贝虚拟机文件时间比较长,因为虚拟机 flat 文件很大,所以要等。脚本完成后,以复制虚拟机文件夹。将以下脚本内容写入文件。_exsi6.7快速克隆centos

好友推荐—基于关系的java和spark代码实现_本关任务:使用 spark core 知识完成 " 好友推荐 " 的程序。-程序员宅基地

文章浏览阅读2k次。本文主要实现基于二度好友的推荐。数学公式参考于:http://blog.csdn.net/qq_14950717/article/details/52197565测试数据为自己随手画的关系图把图片整理成文本信息如下:a b c d e f yb c a f gc a b dd c a e h q re f h d af e a b gg h f bh e g i di j m n ..._本关任务:使用 spark core 知识完成 " 好友推荐 " 的程序。

南京大学-高级程序设计复习总结_南京大学高级程序设计-程序员宅基地

文章浏览阅读367次。南京大学高级程序设计期末复习总结,c++面向对象编程_南京大学高级程序设计

4.朴素贝叶斯分类器实现-matlab_朴素贝叶斯 matlab训练和测试输出-程序员宅基地

文章浏览阅读3.1k次,点赞2次,收藏12次。实现朴素贝叶斯分类器,并且根据李航《统计机器学习》第四章提供的数据训练与测试,结果与书中一致分别实现了朴素贝叶斯以及带有laplace平滑的朴素贝叶斯%书中例题实现朴素贝叶斯%特征1的取值集合A1=[1;2;3];%特征2的取值集合A2=[4;5;6];%S M LAValues={A1;A2};%Y的取值集合YValue=[-1;1];%数据集和T=[ 1,4,-1;..._朴素贝叶斯 matlab训练和测试输出

Markdown 文本换行_markdowntext 换行-程序员宅基地

文章浏览阅读1.6k次。Markdown 文本换行_markdowntext 换行

错误:0xC0000022 在运行 Microsoft Windows 非核心版本的计算机上,运行”slui.exe 0x2a 0xC0000022″以显示错误文本_错误: 0xc0000022 在运行 microsoft windows 非核心版本的计算机上,运行-程序员宅基地

文章浏览阅读6.7w次,点赞2次,收藏37次。win10 2016长期服务版激活错误解决方法:打开“注册表编辑器”;(Windows + R然后输入Regedit)修改SkipRearm的值为1:(在HKEY_LOCAL_MACHINE–》SOFTWARE–》Microsoft–》Windows NT–》CurrentVersion–》SoftwareProtectionPlatform里面,将SkipRearm的值修改为1)重..._错误: 0xc0000022 在运行 microsoft windows 非核心版本的计算机上,运行“slui.ex

推荐文章

热门文章

相关标签