初探MeidaPlayer底层实现(一)

在写网络视频播放器的时候,对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层的实现在下一篇文章。

文章有多处未能解释的代码块,待了解清楚之后再一概补上。未完待续。。。































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值