在Android中可以使用MediaPlayer+SurfaceView来实现一个简单的多媒体播放器。

一  构造函数

  java MediaPlayer class 的源码位置:frameworks\base\media\java\android\media\MediaPlayer.java

  首先看一下其构造函数:

     public MediaPlayer() {

         Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
} mTimeProvider = new TimeProvider(this);
mOpenSubtitleSources = new Vector<InputStream>();
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
mAppOps = IAppOpsService.Stub.asInterface(b); /* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
*/
native_setup(new WeakReference<MediaPlayer>(this)); // 在实例化MediaPlayer对象时,会调用一个native_setup方法
}

  在实例化MediaPlayer对象时,会调用一个native_setup方法:

 private native final void native_setup(Object mediaplayer_this);

  在JNI代码(frameworks\base\media\jni\android_media_MediaPlayer.cpp)中可以找到对应的native函数:

 static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
ALOGV("native_setup");
sp<MediaPlayer> mp = new MediaPlayer(); // 实例化一个native MediaPlayer(frameworks\av\media\libmedia\mediaplayer.cpp)
if (mp == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
} // create new listener and give it to MediaPlayer
sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener); // Stow our new C++ MediaPlayer in an opaque field in the Java object.
setMediaPlayer(env, thiz, mp);
}

  在JNI可以看到,sp<MediaPlayer> mp = new MediaPlayer() 这个native MediaPlayer会去和media service进行交互实现真正的播放功能。

二  设置Listener

  在JNI 函数 android_media_MediaPlayer_native_setup 中有为MediaPlayer设置listener,目的就是通过callback的方式将player的事件上传至java层,以便用户做出对应的处理

     // create new listener and give it to MediaPlayer
sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener);

  从上面这两行代码可以看到,首先我们实例化一个JNIMediaPlayerListener对象,然后将这个对象传递给了C++ MediaPlayer,在frameworks\av\include\media\mediaplayer.h中定义了listener的接口形式:

 // ref-counted object for callbacks
class MediaPlayerListener: virtual public RefBase
{
public:
virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = ;
};

  在JNI代码中,JNIMediaPlayerListener class 正是一个MediaPlayerListener的子类,实现了notify函数,其定义如下:

// ref-counted object for callbacks
class JNIMediaPlayerListener: public MediaPlayerListener
{
public:
JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
~JNIMediaPlayerListener();
virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
private:
JNIMediaPlayerListener();
jclass mClass; // Reference to MediaPlayer class
jobject mObject; // Weak ref to MediaPlayer Java object to call on
};

  callback事件的传递主要是通过notify函数来完成的,下面看一下这个函数的具体实现过程:

void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (obj && obj->dataSize() > ) {
jobject jParcel = createJavaParcelObject(env);
if (jParcel != NULL) {
Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
nativeParcel->setData(obj->data(), obj->dataSize());
env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
msg, ext1, ext2, jParcel);
env->DeleteLocalRef(jParcel);
}
} else {
env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
msg, ext1, ext2, NULL);
}
if (env->ExceptionCheck()) {
ALOGW("An exception occurred while notifying an event.");
LOGW_EX(env);
env->ExceptionClear();
}
}
  • msg, ext1, ext2, obj 携带着事件相关信息及数据;

  • 通过env->CallStaticVoidMethod()方法去回调MediaPlayer(java)的 fields.post_event 方法,并将事件信息及数据传递过去;

  • fields.post_event对应于MediaPlayer的java 方法 postEventFromNative;

  • fields.post_event是在MediaPlayer第一次加载时在android_media_MediaPlayer_native_init中初始化的;

三  小结

  这一篇介绍的内容很简单,主要是对java层的MediaPlayer, JNI层,及native层的MediaPlayer如何关联起来的有个基本的认识与了解。

  简单两点概述:

  1. java层的MediaPlayer提供了java API供用户调用实现playback功能,但其功能的实现还会串接到JNI层,在JNI层会去实例化一个native MediaPlayer,这个native MediaPlayer会和MediaPlayerService进行交互实现真正的播放功能;
  2. 设置listener的目的就是通过回调的方式将来自native的事件进行上传,以便用户在java层做出处理,就这篇而言可以暂时这样理解流程: MediaPlayerService-->native MediaPlayer-->JNI->java MediaPlayer ;

Android MediaPlayer架构 -- 前言小知识点(一)的更多相关文章

  1. Android MediaPlayer架构 -- 前言小知识点(二)

    本文系作者自己学习之所用,文章内容仅出自作者拙劣之思考,问题之处烦请不吝指教. 在frameworks\av\media\libmedia\mediaplayer.cpp中会有语句:const sp& ...

  2. Android MediaPlayer架构 -- MediaPlayer的创建过程

    本文系作者自己学习之所用,文章内容仅出自作者拙劣之思考,问题之处烦请不吝指教. MediaPlayer 能被用来控制音/视频文件或流媒体的回放.Android中以MediaPlayer类作为音视频播放 ...

  3. Android开发之实用小知识点汇总-2

    1.EditText 中将光标移到文字末尾: EditText mEdit = (EditText)this.findViewById(R.id.EditText01); mEdit .setText ...

  4. Android开发之实用小知识点汇总-1

    1.去掉android屏幕中的actionbar: this.requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏 //这个是全屏幕显示的代码 ...

  5. Android 程序申请权限小知识点

    在Google Play 应用商店,显示至少支持设备的数量时候会用到权限数量.其他地方用处不大. Android系统提供为程序提供了权限申请,即在manifest中使用uses-permission来 ...

  6. Android的Activity的小知识点

    1.android的四种启动模式分别是:standard,singleTop,SingleTask,singleInstance. 我们可以在AndroidMainfest.xml中通过Activit ...

  7. Android 绘制view的小知识点

    [onMeasure] 直接继承view或ViewGroup的自定义控件需要重写onMeasure方法并设置wrap_content时的自身大小,否则在布局中使用wrap_content就相当于mat ...

  8. android 小知识点

    小知识点总结 1. android中MotionEvent.ACTION_CANCEL事件如何被触发? 对于这个问题,android文档的说明很简短,想看明白很难.国外一网页说的还比较详细,写在这里分 ...

  9. 改造 Android 官方架构组件 ViewModel

    前言 Android 官方架构组件在今年 5 月份 Google I/O 大会上被公布, 直到 11 月份一直都是测试版, 由于工作比较繁忙, 期间我只是看过类似的文章, 但没有在实际项目中使用过, ...

随机推荐

  1. Java上传文件FTP服务器代码

    1. 在实际的应用重,通常是通过程序来进行文件的上传. 2. 实现java上传文件到ftp服务器中 新建maven项目 添加依赖 <dependency> <groupId>c ...

  2. python 运行日志logging代替方案

    以下是自己写的 记录日志的代码.(和logging不搭嘎,如果如要学loggging模块,本文末尾有他人的链接.) # prtlog.py ############################## ...

  3. Python-HTML 最强标签分类

    编程: 使用(展示)数据 存储数据 处理数据 前端 1. 前端是做什么的? 2. 我们为什么要学前端? 3. 前端都有哪些内容? 1. HTML 2. CSS 3. JavaScript 4.jQue ...

  4. OneNET麒麟座应用开发之六:与气体质量流量控制器通讯

    气体质量流量控制器,简称MFC,通常用于在各种检测中,计量气体的流量.在我们的大气环境数据采集站中,要让气流保持稳定,这样才能准确的获取PM25的数据. 我们采用的气体质量流量控制器具备串口通讯功能, ...

  5. 自适应电脑、手机和iPad的网页设计方法

    随着3G的普及,越来越多的人使用手机上网. 移动设备正超过桌面设备,成为访问互联网的最常见终端.于是,网页设计师不得不面对一个难题:如何才能在不同大小的设备上呈现同样的网页? 手机的屏幕比较小,宽度通 ...

  6. SeaJS入门教程系列之完整示例(三)

    一个完整的例子上文说了那么多,知识点比较分散,所以最后我打算用一个完整的SeaJS例子把这些知识点串起来,方便朋友们归纳回顾.这个例子包含如下文件: 1.index.html——主页面.2.sea.j ...

  7. PHP 将数组的值赋值给一组变量

    经常需要将一个字符串分割成一组值,然后赋值给不同的变量. 逐行赋值非常繁琐,于是查了一下 PHP 中是否有类似 python 中 a, b = (a, b) 的操作. 果然有 $info = arra ...

  8. PHP实现删除字符串中任何字符的函数

    function delStr($start, $end, $orgenStr) { //读取要删除字符位置的前一部分字符串,并赋值给$temp //strpos读取字符第一次出现的位置 //subs ...

  9. php三种常用的加密解密算法

    方法一: /** * @param $string 要加密/解密的字符串 * @param string $operation 类型,ENCODE 加密:DECODE 解密 * @param stri ...

  10. Crack相关

    Microsoft Office 2007专业增强版密钥:KXFDR-7PTMK-YKYHD-C8FWV-BBPVWM7YXX-XJ8YH-WY349-4HPR9-4JBYJCTKXX-M97FT-8 ...