1. Android MultiMedia框架完全解析 - 从开机到MediaServer的注册过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yanbixing123/article/details/88926554

Android的App一般是用java写的,大致流程如下:

MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp){
mediaPlayer.release();
mediaPlayer = null;
}
});
mediaPlayer.setDataSource("abc.mp3"); 
mediaPlayer.setDisplay();
mediaPlayer.prepare();
mediaPlayer.start();

我们就按照这个流程来一步一步分析整个播放流程。

(一)Media Server的启动流程:

我们知道,Android是基于Linux内核的,而在Linux中,启动的第一个进程就是init进程,其他进程都是init进程的子进程。在init进程的启动过程中,会解析Linux的配置脚本init.rc文件,根据init.rc文件的内容,Init进程会装载Android的文件系统,创建系统目录,启动Android系统重要的守护进程,这些进程包括USB守护进程,adb守护进程,vold守护进程等。

同时,init进程还会启动Media Server(多媒体服务),ServiceManager(Binder服务管家)等重要服务。

init进程还会孵化出Zygote进程,Zygote进程是Android系统的首个Java进程,Zygote是所有Java进程的父进程,如图所示:

在Android m6.0之前的版本中,mediaserver服务的启动脚本命令在system/core/rootdir/init.rc文件中:

扫描二维码关注公众号,回复: 5722256 查看本文章

在Android N7.0后,mediaserver服务的启动脚本迁移到system/core/rootdir/init.zygote64.rc文件中:

mediaserver启动后,会把media相关的一些服务添加到ServiceManager中,其中就有MediaPlayerService,ResourceManagerService等等。mediaserver可以理解为所有有关Media相关的服务器,它为app所提供服务。

那么再来看看MediaPlayerService在Android Framework中所处的位置:

这个mediaserver的核心文件就是frameworks/av/media/mediaserver/main_mediaserver.cpp:

int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);

    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    InitializeIcuOrDie();
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
    registerExtensions();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

标红的代码就是MediaPlayerService的初始化代码,它位于frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp中:

void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}

向ServiceManager中注册了一个实名Binder:media.player。

(二)MediaPlayer的创建过程

在App中,我们执行了:MediaPlayer mediaPlayer = new MediaPlayer();

那么就来看看这个过程,在 frameworks/base/media/java/android/MediaPlayer.java中:

 public MediaPlayer() {
        super(new AudioAttributes.Builder().build());

        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>();

        /* 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));
    }

在它的构造函数中,将java中创建的MediaPlayer通过弱引用传递给JNI层,而在它的构造函数之前,MediaPlayer类有一段静态代码块,加载了media_jni.so库,用于JNI相关的初始化:

    static {
        System.loadLibrary("media_jni");
        native_init();
    }

private static native final void native_init();

这里调用了本地方法native_init(),它的实现位于 frameworks/base/media/jni/android_media_MediaPlayer.cpp中,但是,并不能单纯通过名字直接找到这个native_init()方法,它通过一个结构体数组做了映射:

static const JNINativeMethod gMethods[] = {
    {
        "nativeSetDataSource",
        "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
        "[Ljava/lang/String;)V",
        (void *)android_media_MediaPlayer_setDataSourceAndHeaders
    },

    {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
    {"_setDataSource",      "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
    {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
...
    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
    {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
...
}

这个结构体数组几乎映射了所有MediaPlayer类的方法,以后有类似的方法可以通过这个数组找到,下面继续看native_init()方法:

static void
android_media_MediaPlayer_native_init(JNIEnv *env)
{
    jclass clazz;

    clazz = env->FindClass("android/media/MediaPlayer");
    if (clazz == NULL) {
        return;
    }

    fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
    if (fields.context == NULL) {
        return;
    }

    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    if (fields.post_event == NULL) {
        return;
    }

    fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
    if (fields.surface_texture == NULL) {
        return;
    }

    env->DeleteLocalRef(clazz);
.........
}

这里native_init()函数就执行完毕了,它设置了一些java层的方法。然后就是MediaServer的构造函数中的native_setup()函数,它同样位于这个文件中:

static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    ALOGV("native_setup");
    sp<MediaPlayer> mp = new MediaPlayer();
    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);
}

这里创建了一个C++层的MediaPlayer,还设置了一些Listener回调,这个模式和Android的Looper机制差不多,都是java层一个Looper,C++层也有一个Looper。

通过上面的步骤,就发现,从java层想要生成一个MediaPlayer,最终会在C++层中生成一个MediaPlayer()类,至此,MediaPlayer的构造就完成了。

(三)SetDataSource的过程(setDataSource - 1)

在Android App中:mediaPlayer.setDataSource("abc.mp3");

继续在frameworks/base/media/jni/android_media_MediaPlayer.cpp文件中通过那个映射数组找到对应的方法(我们以播放本地文件为例,所以对应的方法就是:

android_media_MediaPlayer_setDataSourceFD):
static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }

    if (fileDescriptor == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return;
    }
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    ALOGV("setDataSourceFD: fd %d", fd);
    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}

首先获取C++层中刚创建的MediaPlayer,然后调用process_media_player_call()来执行MediaPlayer的setDataSource函数并检查返回状态(process_media_player_call()函数这里就不展开了,可以自己看,主要是做了一些错误和异常检测工作,然后notify出去相应的错误状态)。

具体MediaPlayer的setDataSource函数做了什么工作,我们下节再分析,这里只需要知道,java层的setDataSource方法最终调用了C++层MediaPlayer类的setDataSource方法就行。

(四)SetDisplay的过程

在Android App中:mediaPlayer.setDisplay();

在java层:

    public void setDisplay(SurfaceHolder sh) {
        mSurfaceHolder = sh;
        Surface surface;
        if (sh != null) {
            surface = sh.getSurface();
        } else {
            surface = null;
        }
        _setVideoSurface(surface);
        updateSurfaceScreenOn();
    }

private native void _setVideoSurface(Surface surface);

最终会调用到jni层的android_media_MediaPlayer_setVideoSurface()函数,同样在frameworks/base/media/jni/android_media_MediaPlayer.cpp中:

static void
android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
{
    setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
}

static void
setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz); //获取C++层的MediaPlayer
    if (mp == NULL) {
        if (mediaPlayerMustBeAlive) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
        }
        return;
    }

    decVideoSurfaceRef(env, thiz);

    sp<IGraphicBufferProducer> new_st;
    if (jsurface) { //获取java层的surface
        sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
        if (surface != NULL) {
            new_st = surface->getIGraphicBufferProducer();//获取IGraphicBufuferProducer
            if (new_st == NULL) {
                jniThrowException(env, "java/lang/IllegalArgumentException",
                    "The surface does not have a binding SurfaceTexture!");
                return;
            }
            new_st->incStrong((void*)decVideoSurfaceRef);
        } else {
            jniThrowException(env, "java/lang/IllegalArgumentException",
                    "The surface has been released");
            return;
        }
    }

    env->SetLongField(thiz, fields.surface_texture, (jlong)new_st.get());

    // This will fail if the media player has not been initialized yet. This
    // can be the case if setDisplay() on MediaPlayer.java has been called
    // before setDataSource(). The redundant call to setVideoSurfaceTexture()
    // in prepare/prepareAsync covers for this case.
    mp->setVideoSurfaceTexture(new_st);
}

这里主要是对图像现实的surface进行保存,然后将旧的IGraphicBufferProducer强引用减一,再获得新的IGraphicBufferProducer,最终会调用C++层的Media Player的setVideoSurfaceTexture将它折纸进去。

IGraphicBufferProducer是SurfaceFlinger中的内容,一个UI完全现实到display的过程,SurfaceFlinger扮演着重要的角色,但是它的职责是"Flinger",即把所有应用程序最终的绘图结果进行“混合叠图”,然后统一绘制到物理屏幕上。在这个绘图过程中,需要BufferQueue的参与,它是每个应用程序“一对一”的辅导老师,知道着UI程序的“画板申请”,“作画流程”等一系列细节,同时BufferQueue也是IGraphicBufferProducer的服务端,app通过IGraphicBufferProducer来与BufferQueue沟通。

(五)后面的prepare和start过程是直接与C++层MediaPlayer相关了,后面再分析他们。

小结:

本节只是分析了APP层与C++层MediaPlayer的构建过程,让大家对于这个播放流程有个大致的认识和理解。

猜你喜欢

转载自blog.csdn.net/yanbixing123/article/details/88926554