Android Multimedia框架总结(三)MediaPlayer中创建到setDataSource过程

前言:
前一篇的mediaPlayer框架,对于各个模块的关系,得先从核心类MediaPlayer铺开,
同样看下今天的Agenda:

(1)MediaPlayer从create到setDisplay时序图
(2)MediaPlayer的create过程
(3)MediaPlayer的setDataSource过程
(4)MediaPlayer的setDisplay过程

今天分析的是从MediaPlayer创建到MediaPlayer调用setDataSource过程
以往总是把时序图放在最后总结,有些人觉得一上来没有个大概,无从下手,
所以,先把时序图附上,一步一步对着时序图看看每个阶段经历的过程

MediaPlayer从创建到setDisplay时序图

MediaPlayer时序图一(create->setDataSource, 后面文章还有,暂且这么命名):

在这里插入图片描述

MediaPlayer的创建过程

2. create

当外部调用MediaPlayer.create(this,”http://www.xxx.mp4“)时,进入我们MediaPlayer的创建过程:
在这里插入图片描述
以上代码可以总结为:
当MediaPlayer通过Create方式创建播放器时,内部new出MediaPlayer对象 ,并setDataSource,并做好prepare的动作。
这时外面只须调用下start方法,音视频资源将能播放起来。

通常我们用通过构造MediaPlayer,然后自己setDataSource,prepare等操作。
无论哪种都要先经过new MediaPlayer(),我们看下构造中做了什么操作:
在这里插入图片描述

注意这里有个EventHandler,虽然今天不是重点要说的,我们可以先了解下它:
在这里插入图片描述

3. new mediaplayer

接下来看native层如何创建一个mediaplayer,
在说native_up之前,我们注意,一般加载so都是在静态代码块中,
在MediaPlayer中有一段静态代码块,用于初始jni相关,早于构造方法,在加载类时就执行。
一般是全局性的数据,变量,可以放在这。这里是加载media_jni.so文件。
在这里插入图片描述
开始进入android_media_MediaPlayer.cpp分析,第一个方法,就是在java静态代码块调入的native_init:
在这里插入图片描述
被native层调用,就是反向调用,仅被使用EventHandler post事件回到主线程中,
很多用post开头,基本都是post到主线程,用软引用指向原生的MediaPlayer,以便native代码是安全的,
当MediaPlayer可在native释放,调到java中的实现部分如下:
在这里插入图片描述
以上就是native_init方法,可以看到,就是做了一些准备工作,获取一些方法,一些要用的成员变量。
接着回到之前说的,create中MediaPlayer构造函数,有一个native_setup,
在android_media_MediaPlayer.cpp找到对应方法:
在这里插入图片描述
可以看到会设置一些回调用的listener及创建c++中的MediaPlayer对象.

10. MediaPlayer的setDataSource过程

上面就是MediaPlayer的构造过程:构造后接下来要设置数据源,进而到了setDataSource操作,
我们看下setDataSource做了什么操作:
在这里插入图片描述
在这里插入图片描述
先看看如果送的setDataSource中的uri是文件类型:
在这里插入图片描述
开始进入jni层,发现找不到android_media_MediaPlayer_setDataSource方法,
可以发现有一个方法名对应映射方法声明:
在这里插入图片描述
以上这个方法名字映射,如果看过JNIEnv * 源码的话,对上面这些并不陌生,无非也是映射,不影响我们分析,
在这里我们接下来要去找android_media_MediaPlayer_setDataSourceFD这个函数看看:
在这里插入图片描述
接着看process_media_player_call方法:
在这里插入图片描述
以上代码总结为:当 mp->setDataSource(fd, offset, length)方法后得到status后,对各种状态进行notify。
有异常的直接抛出,这样也就不会影响mediaplayer后面的执行过程。
接下来看下以http/rtsp传入到jni中,在java层对应的nativeSetDataSource方法:
在这里插入图片描述

12. android_media_MediaPlayer_setDataSourceAndHeaders

在jni中通过映射表,可对应到android_media_MediaPlayer_setDataSourceAndHeaders:
在这里插入图片描述
到此,setDataSource的过程就完成了。
这里要注意两个点,
一个是从Java->jni->c++正向调用过程(前面从java到native都是正向过程),
一种是c++ -> jni -> java层过程(如 mp->setDataSource( httpService, pathStr, headersVector.size() > 0? &headersVector : NULL),那有人肯定会问了?这样来回调的好处是什么?

  1. 安全性,封装在native层的代码以so形式,破环性风险小
  2. 效率快,在运行速度上c++执行时间快,且底层也是c++写的。可以对复杂的渲染及对时间要求高的,放在native是最好不过的选择了。
  3. 连通性,正向调用将值进行传入,反向调用把处理过值通知回去。相当于一根管道一样。

14. MediaPlayer的setDisplay过程

接下来看下在setDataSource之后,开始进行mp.setDisplay(holder)
MediaPLayer.java -> setDisplay
在这里插入图片描述
对于2,同样在android_media_MediaPlayer.cpp找到其对应方法:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里有几个概念要理解下:

  1. SurfaceTexture
    SurfaceTexture是从Android3.0(API 11)加入的一个新类。
    这个类跟SurfaceView很像,可以从video decode里面获取图像流(image stream)。
    但是,和SurfaceView不同的是,SurfaceTexture在接收图像流之后,不需要显示出来。
    SurfaceTexture不需要显示到屏幕上,因此我们可以用SurfaceTexture接收来自decode出来的图像流,
    然后从SurfaceTexture中取得图像帧的拷贝进行处理,处理完毕后再送给另一个SurfaceView用于显示即可。

  2. Surface
    处理被屏幕排序的原生的buffer,
    Android中的Surface就是一个用来画图形(graphics)或图像(image)的地方,
    对于View及其子类,都是画在Surface上,
    各Surface对象通过Surfaceflinger合成到frameBuffer,每个Surface都是双缓冲(实际上就是两个线程,一个渲染线程,一个UI更新线程),它有一个backBuffer和一个frontBuffer,Surface中创建了Canvas对象,用来管理Surface绘图操作,Canvas对应Bitmap,存储Surface中的内容。

  3. SurfaceView
    这个可能经常被说起,在Camera,MediaRecorder,MediaPlayer中用来显示图像的。
    SurfaceView是View的子类,且实现了Parcelable接口 且 实现了Parcelable接口,其中内嵌了一个专门用于绘制的Surface,SurfaceView可以控制这个Surface的格式和尺寸,以及Surface的绘制位置。
    可以理解为Surface就是管理数据的地方,SurfaceView就是展示数据的地方。

  4. SurfaceHolder
    顾名思义,一个管理SurfaceHolder的容器。SurfaceHolder是一个接口,可理解为一个Surface的监听器。
    通过回调方法addCallback(SurfaceHolder.Callback callback )监听Surface的创建 ,通过获取Surface中的Canvas对象,并锁定之。
    所得到的Canvas对象 ,通过当修改Surface中的数据完成后,释放同步锁,并提交改变Surface的状态及图像,将新的图像数据进行展示。

  5. 而最后综合
    SurfaceView中调用getHolder方法,可以获得当前SurfaceView中的Surface对应的SurfaceHolder,SurfaceHolder开始对Surface进行管理操作。
    这里其实按MVC模式理解的话,可以更好理解。
    M:Surface(图像数据),V:SurfaceView(图像展示),C:SurfaceHolder(图像数据管理)。
    MediaPlayer.java中setDisPlay的操作就是对将要显示的视频设预设置。
    以上就是setDisPlay过程,java中setDisPlay最后一行,就是通过jni返回的Surface,时时做好更新准备。




本文转自: http://blog.csdn.net/hejjunlin/article/details/52392430
发布了324 篇原创文章 · 获赞 54 · 访问量 7万+
展开阅读全文

MediaPlayersetDataSource出错

10-14

我想用service播放音乐 直接上代码: private static final MediaPlayer mp = new MediaPlayer(); private String songId; private int op; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub // mp = new MediaPlayer(); mp.setOnCompletionListener(this); System.out.println("start mediaplayer"); } public void onDestroy() { System.out.println("stop mediaplayer"); if (mp != null) { mp.stop(); mp.release(); } } @Override public void onCompletion(MediaPlayer mp) { // TODO Auto-generated method stub MainActivity.next(); } @Override @Deprecated public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub } public void option() { switch (op) { case 1: mp.stop(); break; case 2: playMusic(); break; default: Toast.makeText(this, "无法找到操作码", Toast.LENGTH_SHORT).show(); break; } } public void playMusic() { System.out.println("start playing music"); if (mp.isPlaying()) { mp.stop(); } Uri uri = Uri.withAppendedPath( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, songId); System.out.println("uri is wrong"); try { mp.reset(); mp.setDataSource(MusicService.this, uri); // mp.setLooping(true); mp.prepare(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } mp.start(); } public void OnMp3Change(String songId, int op) { // TODO Auto-generated method stub System.out.println("MusicService:" + songId); this.songId = songId; this.op = op; option(); } 最后在playMusic中的mp.setDataSource(MusicService.this, uri)这里报错。 10-14 07:51:23.515: W/System.err(10908): java.lang.NullPointerException 10-14 07:51:23.519: W/System.err(10908): at android.content.ContextWrapper.getContentResolver(ContextWrapper.java:99) 10-14 07:51:23.522: W/System.err(10908): at android.media.MediaPlayer.setDataSource(MediaPlayer.java:876) 10-14 07:51:23.522: W/System.err(10908): at android.media.MediaPlayer.setDataSource(MediaPlayer.java:854) 10-14 07:51:23.522: W/System.err(10908): at com.example.scanmusic.MusicService.playMusic(MusicService.java:85) 10-14 07:51:23.522: W/System.err(10908): at com.example.scanmusic.MusicService.option(MusicService.java:62) 10-14 07:51:23.525: W/System.err(10908): at com.example.scanmusic.MusicService.OnMp3Change(MusicService.java:113) 10-14 07:51:23.525: W/System.err(10908): at com.example.scanmusic.MainActivity.onListItemClick(MainActivity.java:138) 10-14 07:51:23.525: W/System.err(10908): at android.app.ListActivity$2.onItemClick(ListActivity.java:319) 10-14 07:51:23.525: W/System.err(10908): at android.widget.AdapterView.performItemClick(AdapterView.java:301) 10-14 07:51:23.525: W/System.err(10908): at android.widget.AbsListView.performItemClick(AbsListView.java:1100) 10-14 07:51:23.529: W/System.err(10908): at android.widget.AbsListView$PerformClick.run(AbsListView.java:2749) 10-14 07:51:23.529: W/System.err(10908): at android.widget.AbsListView$1.run(AbsListView.java:3430) 10-14 07:51:23.529: W/System.err(10908): at android.os.Handler.handleCallback(Handler.java:725) 10-14 07:51:23.529: W/System.err(10908): at android.os.Handler.dispatchMessage(Handler.java:92) 10-14 07:51:23.529: W/System.err(10908): at android.os.Looper.loop(Looper.java:137) 10-14 07:51:23.529: W/System.err(10908): at android.app.ActivityThread.main(ActivityThread.java:5106) 10-14 07:51:23.532: W/System.err(10908): at java.lang.reflect.Method.invokeNative(Native Method) 10-14 07:51:23.532: W/System.err(10908): at java.lang.reflect.Method.invoke(Method.java:511) 10-14 07:51:23.532: W/System.err(10908): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:821) 10-14 07:51:23.532: W/System.err(10908): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:588) 10-14 07:51:23.532: W/System.err(10908): at dalvik.system.NativeStart.main(Native Method) 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 黑客帝国 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览