private static void postEventFromNative(Object mediaplayer_ref,
int what, int arg1, int arg2, Object obj)
{
//得到弱引用的MediaPlayer
final MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();
if (mp == null) {
return;
}
…
//如果handler不为空,则发送一条message
if (mp.mEventHandler != null) {
Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
mp.mEventHandler.sendMessage(m);
}
}
postEventFromNative总结
总的来说,就是拿到Native层创建好的MediaPlayer,并且向Handler发送一条message,至于后面做了啥之后再讲。
我们之前在create()的时候,创建MediaPlayer之后,会走native_setup方法,我们来看看这个方法做了什么:
//android_media_MediaPlayer.cpp
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
ALOGV(“native_setup”);
sp mp = new MediaPlayer();
…
// 给MediaPlayer创建一个Listener,便于我们在Java层设置的 setPrepareListener、setOnCompleteListener能产生回调
sp listener = new JNIMediaPlayerListener(env, thiz, weak_this);
mp->setListener(listener);
// 对于Java层来说,C++中的MediaPlayer是不透明的,也无需关心其对应的逻辑,各司其职就行了
setMediaPlayer(env, thiz, mp);
}
native_setup总结
-
设置监听器
-
C++层自己处理这个MediaPlayer
上面是一个MediaPlayer的构造过程,在构造完,着实的获取到MediaPlayer这个对象之后,我们就会去 setDataSource(),我们来看看它的源码(注:这一段代码比较无聊,可以大致浏览一下并直接看总结):
(注:下面一段是传入的uri为文件资源形式的代码,就比如我们传了一个本地的媒体文件
private void setDataSource(String path, Map<String, String> headers, List cookies)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
{
String[] keys = null;
String[] values = null;
if (headers != null) {
keys = new String[headers.size()];
values = new String[headers.size()];
int i = 0;
//把HTPP/RTSP中包含的key、value分别装到两个数组中
for (Map.Entry<String, String> entry: headers.entrySet()) {
keys[i] = entry.getKey();
values[i] = entry.getValue();
++i;
}
}
setDataSource(path, keys, values, cookies);
}
private void setDataSource(String path, String[] keys, String[] values,
List cookies)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
//解析path
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
if (“file”.equals(scheme)) {
path = uri.getPath();
} else if (scheme != null) {
// 处理非资源文件
nativeSetDataSource(
MediaHTTPService.createHttpServiceBinderIfNecessary(path, cookies),
path,
keys,
values);
return;
}
//处理文件类型
final File file = new File(path);
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
//得到文件标识符
FileDescriptor fd = is.getFD();
//传入文件标志符
setDataSource(fd);
is.close();
} else {
throw new IOException(“setDataSource failed.”);
}
}
public void setDataSource(FileDescriptor fd)
throws IOException, IllegalArgumentException, IllegalStateException {
setDataSource(fd, 0, 0x7ffffffffffffffL);
}
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException {
//进入native层
_setDataSource(fd, offset, length);
}
setDataSource()总结
解析uri,如果得到的路径是文件,则把该文件资源的资源标识符丢给native层处理。
native层并没有setDataSource函数,但是有一个函数名映射函数说明,这是JNI中常用的动态注册方法:
所以我们找到 setDataSourceFD()
:
static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
//获得MediaPlayer
sp mp = getMediaPlayer(env, thiz);
…
//在JNI中获取 java.i