MediaPlayer基本使用总结

一、简介

MediaPlayer是Android当中开发音视频应用的一个重要组件,它不仅支持本地音视频的播放,同时也能够播放网络的音视频,支持多种视频播放格式,例如m3u8、mp4、3gp等,其与底层直接进行交互,调用底层的native方法,同时其内部包含了很多关于操作音视频播放的方法。因为MediaPlayer直接与底层进行交互,开发者对其的使用存在比较繁琐的问题,后续的Android版本通过封装MediaPlayer中的方法,同时实现MediaPlayerControl接口、继承SurfaceView类、推出了面向开发者更为友好的音视频播放组件VideoView,但其实质上还是对MediaPlayer中的方法进行调用。

MediaPlayer类是媒体框架最重要的组成部分之一。此类的对象能够获取、解码以及播放音频和视频,而且只需极少量设置。它支持多种不同的媒体源,例如:

本地资源
内部URI,例如您可能从内容解析器那获取的URI

外部网址(流式传输)

Android下对于音频、视频的支持均需要使用到MediaPlayer,它主要用来控制Android下播放文件或流的类。MediaPlayer处于Android多媒体包下"android.media.MediaPlayer",仅有一个无参的构造函数,虽然仅为我们提供了一个无参的构造函数,为了方便我们初始化,还为我们提供了几个静态的create()方法用于完成MediaPlayer初始化的工作。

static MediaPlayer create(Context context,int resid):通过音频资源的Id来创建一个MediaPlayer实例
static MediaPlayer create(Context context,Uri uri):通过一个音频资源的Uri地址来创建一个MediaPlayer实例

MediaPlayer除了通过上面两个create()方法在初始化的时候指定媒体资源,还可以通过MediaPlayer.setDataSource()方法为初始化后的MediaPlayer设置媒体资源,setDataSource()具有多个重载函数,适用于不同的媒体资源来源

void setDataSource(String path):通过一个媒体资源的地址指定MediaPlayer的数据源,这里的path可以是一个本地路径,也可以是网络路径
void setDataSource(Context context,Uri uri):通过一个Uri指定MediaPlayer的数据源,这里的Uri可以是网络路径或者一个内容提供者的Uri
void setDataSource(FileDescriptor fd):通过一个FileDescriptor指定一个MediaPlayer的数据源

setDataSource (FileDescriptor fd, long offset, long length)

其中使用FileDescriptor时,需要将文件放到与res文件夹平级的assets文件夹里,然后使用:

AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());

例如:

(1)如何获得MediaPlayer实例:
可以使用直接new的方式:
MediaPlayer mp = new MediaPlayer();
也可以使用create的方式,如:
MediaPlayer mp = MediaPlayer.create(this, R.raw.test);//这时就不用调用setDataSource了

(2)如何设置要播放的文件:
MediaPlayer要播放的文件主要包括3个来源:
a. 用户在应用中事先自带的resource资源
例如:MediaPlayer.create(this, R.raw.test);
b. 存储在SD卡或其他文件路径下的媒体文件
例如:mp.setDataSource("/sdcard/test.mp3");
c. 网络上的媒体文件
例如:mp.setDataSource(“http://www.citynorth.cn/music/confucius.mp3”);

二、MediaPlayer的api使用

MediaPlayer其实是一个封装的很好的音频、视频流媒体操作类,如果查看其源码,会发现其内部是调用的native方法,所以它其实是有C++实现的。
  既然是一个流媒体操作类,那么必然涉及到,播放、暂停、停止等操作,实际上MediaPlayer也为我们提供了相应的方法来直接操作流媒体。
• void start():开始或恢复播放。
• void stop():停止播放。
• void pause():暂停播放。

• int getDuration():获取流媒体的总播放时长,单位是毫秒。
• int getCurrentPosition():获取当前流媒体的播放的位置,单位是毫秒。
• void seekTo(int msec):设置当前MediaPlayer的播放位置,单位是毫秒。
• void setLooping(boolean looping):设置是否循环播放。
• boolean isLooping():判断是否循环播放。
• boolean isPlaying():判断是否正在播放。
• void prepare():同步的方式装载流媒体文件。
• void prepareAsync():异步的方式装载流媒体文件。
• void release ():回收流媒体资源。
• void setAudioStreamType(int streamtype):设置播放流媒体类型。
• void setWakeMode(Context context, int mode):设置CPU唤醒的状态。
• setNextMediaPlayer(MediaPlayer next):设置当前流媒体播放完毕,下一个播放的MediaPlayer。

• setOnCompletionListener(MediaPlayer.OnCompletionListener listener):当流媒体播放完毕的时候回调。
• setOnErrorListener(MediaPlayer.OnErrorListener listener):当播放中发生错误的时候回调。
• setOnPreparedListener(MediaPlayer.OnPreparedListener listener):当装载流媒体完毕的时候回调。
• setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener):当使用seekTo()设置播放位置的时候回调

三、MediaPlayer使用技巧

在使用MediaPlayer的使用过程中,有个小技巧需要说明一下:
1、在使用start()播放流媒体之前,需要装载流媒体资源。这里最好使用prepareAsync()用异步的方式装载流媒体资源。因为流媒体资源的装载是会消耗系统资源的,在一些硬件不理想的设备上,如果使用prepare()同步的方式装载资源,可能会造成UI界面的卡顿,这是非常影响用于体验的。因此推荐使用异步装载的方式,为了**避免还没有装载完成就调用start()而报错的问题,需要绑定MediaPlayer.setOnPreparedListener()**事件,它将在异步装载完成之后回调。异步装载还有一个好处就是避免装载超时引发ANR((Application Not Responding)错误。

2、使用MediaPlayer最好使用一个Service来使用,并且在Service的onDestory()方法中回收MediaPlayer资源,实际上,就算是直接使用Activity承载MediaPlayer,也最好在销毁的时候判断一下MediaPlayer是否被回收,如果未被回收,回收其资源,因为底层调用的native方法,如果不销毁还是会在底层继续播放,而承载的组件已经被销毁了,这个时候就无法获取到这个MediaPlayer进而控制它。

3、因为MediaPlayer一直操作的是一个流媒体,所以无可避免的可能一段流媒体资源,前半段可以正常播放,而中间一段因为解析或者源文件错误等问题,造成中间一段无法播放问题,需要我们处理这个错误,否则会影响Ux(用户体验)。可以为MediaPlayer注册回调函数setOnErrorListener()来设置出错之后的解决办法,一般重新播放或者播放下一个流媒体即可。

四、MediaPlayer状态机

当MediaPlayer被创建出来时,此时就处于Idle就绪状态;当调用setDataSource传入需要播放的音视频资源时,此时MediaPlayer的状态从Idle就绪状态变为Initialized初始化状态;调用prepared同步方法或者调用preparedAsync异步方法,都是让MediaPlayer去准备需要的资源,但两者不同的是,prepared同步方法在准备得时候会阻塞线程,直到资源准备完毕时线程才能执行其他工作,而preparedAsync异步方法不会阻塞线程其他工作的执行,内部通过回调方法来通知外部MediaPlayer资源准备好的时机,当准备好之后,此时MediaPlayer变更为Prepared状态;处于Prepared状态时,意味着用户就可以成功设置如音视频音量等属性了,当调用start方法,MediaPlayer的状态就会变更为Started,一般该方法会在preparedAsync的回调方法中进行调用,即只要资源准备完毕,就可以调用start方法播放音视频资源了;此时若调用pause方法,音视频就会处于Pause暂停状态,当再次调用start方法时,MediaPlayer重新回到Started状态,音视频恢复之前暂停的位置;当调用stop方法,此时MediaPlayer将处于Stop的状态,这时候的MediaPlayer要想重新进入Started状态,只能重新调用prepared或者preparedAsync方法,直至到Prepared状态以后才能通过调用MediaPlayer中的start方法重新回到Startd状态;最后当视频播放结束的时候,只要注册了setOnCompletionListener监听器,MediaPlayer就会进行回调,告诉用户此音视频资源已经播放完毕,此时MediaPlayer处于PlaybackCompleted状态。

if (Textutils.equals(text,b:“开始"))ibtn_opt.setText(“结束");mediaPlayer = new MediaP1ayer();//设置准备监听mediaPlayer.setOnPreparedListener(this);mediaPlayer.setOncompletionListener(this);int duration = mediaPlayer.getDuration();int currentPosition = mediaPlayer.getcurrentPosition();
try{//指定视频源mediaPlayer.setDataSource(new File(getExternalFilesDir( type:""),child: "a.mp4" ).getAbsolutePath());}catch (IOException e){e.printstackTrace();
}mediaPlayer.setSurface(new Surface(textureView.getSurfaceTexture()));mediaPlayer.prepareAsync();
}else {btn_opt.setText("开始");mediaPlayer.stop();mediaPlayer.release();
}@override
public void onPrepared(MediaPlayer mp){mediaplayer.start();
}

五、MediaPlayer架构详解

创建MediaPlayer的过程

通过jni,调用native层,即android_media_MediaPlayer.cpp

/frameworks/base/media/java/android/media/MediaPlayer.java

new MediaPlayer()调用MediaPlayer.cpp

framework/base/media/jni/android_media_MediaPlayer.cpp

对象的构造函数分析:
其实就是一些字段默认值的初始化

/frameworks/av/media/libmedia/mediaplayer.cpp

注意:与MediaRecorder的区别就在于MediaRecord.cpp的构造函数中就已经开始getMediaPlayerService().createMediaRecorder(),而MediaPlayer.cpp的构造函数中仅仅做了一些初始化变量的操作,真正创建MediaPlayer还是在setDataSource()中。

在java层MediaPlayer.java的setDataSource()各个重载方法中会调用到三个native层的方法

这三个native方法在jni层的调用声明如下:
即它们是通过JNI的方法映射对应别名方法的调用

最终在frameworks/base/media/jni/android_media_MediaPlayer.cpp中mp --> setDataSource(),调用到了frameworks/av/media/libmedia/mediaplayer.cpp的setDataSource()方法

MediaPlayer.cpp的setDataSource()方法中,getMediaPlayerService() --> create(),从ServiceManager中先获得BpMediaPlayerService对象,即Bn对象的在客户端的代理操作对象,并调用create()方法,具体的实现就在IMediaPlayerService.cpp中

service->create(this, mAudioSessionId)实现分析

frameworks/av/media/libmedia/IMediaPlayerService.cpp

根据Binder实现机制,直接定位到服务端的Bn实现端即BnMediaPlayerService的onTransact()方法处理【CREATE】事务事件流程

create(client, audioSessionId)实现分析:
通过分析可知,BnMediaPlayerService的子类实现了该方法,即MediaPlayerService实现类

frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

Client类声明和构造函数实现(即Client就是继承至BnMediaPlayer播放器对象):

/frameworks/av/media/libmediaplayerservice/MediaPlayerService.h

六、MediaPlayer架构总结

与MediaRecorder的区别就在于MediaRecord.cpp的构造函数中就已经开始getMediaPlayerService().createMediaRecorder(),而MediaPlayer.cpp的构造函数中仅仅做了一些初始化变量的操作,真正创建MediaPlayer还是在setDataSource()中。

(1) MediaPlayer.java # new MediaPlayer(),构造函数调用android_media_MediaPlayer.cpp

–> android_media_MediaPlayer.cpp # native_setup()中调用new MediaPlayer()

–> MediaPlayer.cpp # MediaPlayer() ,但是这个里面仅仅进行了一些初始化变量的操作,真正的MediaPlayer还未创建

(2) MediaPlayer.java # setDataSource()中会调用native层的android_media_MediaPlayer_setDataSourceFD()等方法
–> android_media_MediaPlayer.cpp # android_media_MediaPlayer_setDataSourceFD()中还是会调用mp ->setDataSource(),即MediaPlayer.cpp中的setDataSource()方法
–> MediaPlayer.cpp # setDataSource()中调用getMediaPlayerService().create(),getMediaPlayerService()从ServiceManager中获取BpMediaPlayerService,即Bn对象的在客户端的代理操作对象
–> IMediaPlayerService.cpp # create(),这里其实都是BpMediaPlayerService正在执行remote() ->transact(CREATE),将CREATE消息通过binder发送出去
–> IMediaPlayerService.cpp # onTransact(),这里是BnMediaPlayerService在进行处理,当消息为CREATE时,调用MediaPlayerService 中的create()函数
–> MediaPlayerService.cpp#create(),这里会new Client(),这里的Client其实就是BnMediaPlayer的子类。

MediaPlayer相关推荐

  1. android mp4宽高,Android:MediaPlayer视频宽高比问题

    我遇到了一个我无法解决的问题.我正在使用MediaPlayer类来播放视频;但是,我总是失去原有的宽高比.这里提到了媒体播放器代码和xml代码.我尝试了很多东西,但仍然无法解决问题.我需要保持原始的宽 ...

  2. android mediaplayer状态机

    对播放音频/视频文件和流的控制是通过一个状态机来管理的.下图显示一个 MediaPlayer 对象被支持的播放控制操作驱动的生命周期和状态.椭圆代表 MediaPlayer 对象可能驻留的状态.弧线表 ...

  3. android vlc 参数,【VLC-Android】LibVLC API简介(至关于VLC的MediaPlayer)

    前言html 学新东西API很重要,这里抛砖引玉整理了一下,欢迎反馈!android 声明 欢迎转载,但请保留文章原始出处:) 博客园:http://www.cnblogs.com 农民伯伯: htt ...

  4. Android--MP3播放器MediaPlayer

    MediaPlayer 上面提到过,Android下对于音频.视频的支持均需要使用到MediaPlayer,它主要用来控制Android下播放文件或流的类.MediaPlayer处于Android多媒 ...

  5. MediaPlayer开发全解析

    本文介绍MediaPlayer的使用.MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoView比MediaPlayer简单易用,但定制性不如用Med ...

  6. android播放器:mediaplayer

    近几天的主要问题在于播放器.原来采用的方案最终发现存在问题无法实施,只好临时替换.想起最开始就曾经想用的android提供的VideoView和MediaPlayer组件,开始替换,然后就是一堆问题. ...

  7. 采用Android的MediaPlayer+SurfaceView设计视频播放器

    前言 android视频播放有很多方式(自带videoView等),这里简单说其中一种:MediaPlayer+SurfaceView,一个播放音频,一个播放视频(图像). 大体结构图 BaseMed ...

  8. UWP_Homework_4 A MediaPlayer

    这次的作业任务是在上一次完成的MediaPlayer的基础上添加两个新功能, 第一,从网上直接播放文件, 第二,从网上下载文件. 首先我添加了两个button和一个textbok,并且重新做了一下界面 ...

  9. Android开发--多媒体应用开发(一)--MediaPlayer的使用介绍

    MediaPlayer用于播放音频文件,它的使用非常简单,使用这个类播放音频文件有两种方法,下面就这两种方法分别进行介绍. 一,使用构造函数 可以使用直接new的方式: MediaPlayer mp ...

  10. Android--制作开场动画/MediaPlayer.OnCompletionListener

    我们在玩游戏的时候常常会现有一个开场动画,要实现这个并不难,下面将给出一个实例实现开场动画. 这个实例需要两个Activity,一个作为开场动画,一个是主程序界面,由于并不需要演示其他的东西,所以在第 ...

最新文章

  1. python切片语法-如何在Python中使用省略号切片语法?
  2. python工具-文件及文件夹移动及处理
  3. 蓝桥杯练习系统习题-算法提高2
  4. 用API获得Internet Explorer_Server类的HTML
  5. linux下怎么退出telnet
  6. 计算机用并行传输还是串行,网线RJ45是并行传输还是串行
  7. matlab中打不开保存好的模糊控制器,(完整版)matlab模糊控制工具箱的使用
  8. 1-2-3 CodeForces - 863C(规律+思维)
  9. HttpContext(三)-Request
  10. Nuget多项目批量打包上传服务器的简明教程
  11. 查看数据库 MySQL 的版本信息的命令语句
  12. java key锁_Java细粒度锁实现的3种方式
  13. 高校邦后台挂课答题助手可后台可多开可答题
  14. 内网服务器软件共享文件,服务器共享文件夹设置软件、局域网共享文件夹加密工具、文件共享服务器软件的选择...
  15. 宇宙飞船大战html5游戏,GitHub - WildDogTeam/demo-js-starwars: 基于WildDog的太空大战游戏...
  16. XYplorer使用教程
  17. gdb: warning Can‘t open file /usr/lib/libstdc++.so.6.0.19 during file-backed mapping note processing
  18. DOTA全英雄装备介绍+物品简称[图文]
  19. 测验1: Python快速入门 (第2周)
  20. 《The Forward-Forward Algorithm: Some Preliminary Investigations》

热门文章

  1. c++/MFC CSocket仿QQ聊天软件,实现1对1聊天,群聊
  2. 2020天池 “数字人体”视觉挑战赛_VNNI赛道_冠军_方案分享
  3. dhtmlx甘特图--vue2
  4. java的抽象方法_java抽象方法是什么
  5. 用于二维范德华异质结构表征的低温探针台
  6. 除了成本低、获客快等,企业直播还有什么优势呢?
  7. 安卓课程设计之记账本_课程设计:基于安卓的记账本.doc
  8. C++ 大作业 记账本
  9. Centos 文件和目录访问权限设置
  10. 计算机智能科学与技术专业大学排名,全国智能科学与技术专业大学排名