在写网络视频播放器的时候,对MediaPlayer框架有很多不了解的地方,比如不了解其缓冲机制无法实现具体的播放功能。于是想对MeidaPlayer进行深入了解,趁此对framework层源码进行研究来加深对android系统的学习。
先看下简单的播放网络视频实现代码:
mMediaPlayer=new MediaPlayer();
mMediaPlayer.setDataSource(url);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.prepare();
mMediaPlayer.setDisplay(holder);
mMediaPlayer.start();
先看下MediaPlayer类的构造函数,位置在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));
}
继续
looper = Looper.myLooper()
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
因为整个实现都在主线程中,此处返回的应该是主线程中的Looper。//todo 暂时先不深入了解。
继续
if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
}
EventHandler类是MediaPlayer类中的内部类,下面是构造方法
public EventHandler(MediaPlayer mp, Looper looper) {
super(looper);
mMediaPlayer = mp;
}
继续
mTimeProvider = new TimeProvider(this);
TimeProvider类也是MediaPlayer类中的内部类。先来看下构造
public TimeProvider(MediaPlayer mp) {
mPlayer = mp;
try {
getCurrentTimeUs(true, false);//todo 获取时间,具体功能先不了解
} catch (IllegalStateException e) {
// we assume starting position
mRefresh = true;
}
Looper looper;
if ((looper = Looper.myLooper()) == null && //上面分析过looper不会为null
(looper = Looper.getMainLooper()) == null) { // Create our own looper here in case MP was created without one
mHandlerThread = new HandlerThread("MediaPlayerMTPEventThread", Process.THREAD_PRIORITY_FOREGROUND); mHandlerThread.start(); looper = mHandlerThread.getLooper(); } mEventHandler = new EventHandler(looper);//构造一个EventHandler对象
//OnMediaTimeListener数组
mListeners = new MediaTimeProvider.OnMediaTimeListener[0];
mTimes = new long[0]; mLastTimeUs = 0; mTimeAdjustment = 0;}
继续
mOpenSubtitleSources = new Vector<InputStream>();//todo 具体不知道干嘛的
继续
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);//todo 获取服务具体先不了解
mAppOps = IAppOpsService.Stub.asInterface(b);//todo 先不了解
继续
/* 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));
原函数如下,是个本地函数,得到JNI层去了解。private native final void native_setup(Object mediaplayer_this);
以上就是MeidaPlayer的构造函数的具体实现,另外在类中有一处静态代码块如下:
static {
System.loadLibrary("media_jni");//加载库
native_init();//本地初始化,
}
private static native final void native_init();
同样是本地函数。
继续
mMediaPlayer.setDataSource(url);
源码如下
@param path the path of the file, or the http/rtsp URL of the stream you want to play
public void setDataSource(String path)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
setDataSource(path, null, null);
}
接着跳转到
private void setDataSource(String path, String[] keys, String[] values)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
final Uri uri = Uri.parse(path);//转换为uri
final String scheme = uri.getScheme();//获取域名
if ("file".equals(scheme)) {//如果是file
path = uri.getPath();
} else if (scheme != null) {//否则不为空,传入的是网络地址,所以进入这里
// handle non-file sources
nativeSetDataSource(
MediaHTTPService.createHttpServiceBinderIfNecessary(path),
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.");
}
}
接着跳转
private native void nativeSetDataSource(
IBinder httpServiceBinder, String path, String[] keys, String[] values)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
同样是本地函数。
本章只有JAVA层实现,JNI层的实现在下一篇文章。
文章有多处未能解释的代码块,待了解清楚之后再一概补上。未完待续。。。