android多媒体开发笔记

来源:互联网 发布:老炮儿网络剧全集 编辑:程序博客网 时间:2024/06/05 04:43

一:上层mediaPlayer 是如何调到Stagefright的

[java]

mediaPlayer=new MediaPlayer(); 

mediaPlayer.setDataSource(path); 

mediaPlayer.setDisplay(surfaceView.getHolder()); 

mediaPlayer.prepare(); 

mediaPlayer.start();  

不用考虑文件来源、协议、文件容器格式、文件音视频格式等等有关技术,只需遵循SDK接口规范简单几步就能把视频播出来。这也是android这个软件栈所要达到的目的。但是真正的播放器功能实现是在frameworks层,主要是Stagefright。
在我们研究Stagefright之前,有个问题需要解决:上层mediaPlayer 是如何调到Stagefright的?


   先来张android的架构图,android的分层结构还是很清晰的。但是上层的java程序是不是顺序的一层一层调到media framework的呢?,如果按照传统的这种思想看代码的话你的脑袋都会看大。所以这里要先稍稍解释一下android的灵魂 binder。binder是android 系统下的一种IPC机制。是进程间交互的一种方式。在开发android应用时,脑袋一定要一直保持C/S结构的思想。android应用的开发说白了就是通过android提供的一系列的服务来完成自己的目的。apk是一个独立的进程,android的系统服务也是很多个独立的进程。binder的功能就是把client 和 service 连接起来。

来张简图


在你我开发应用之前,android已经为我们提供了很多种service服务。包括mediaplayerser 这种视频播放的服务,所以我们开发应用就会很简单,只需申请这些服务就行。如果把这些服务看成是姑娘们,当然需要一个嬷嬷来管理这些姑娘,因为在你没给钱之前嬷嬷不会让你和姑娘见面,为你服务。这个嬷嬷就是Service Manager,Service Manager这个嬷嬷手中有个姑娘的表,新来的姑娘都会先来这里登记一下姓名和住址信息。这个时候你(client)来了,你需要一个擅长播放的姑娘(service)为你服务。你需要先联系嬷嬷,嬷嬷会根据你的需求查表来找到这个播放的姑娘,接下来这个姑娘就为你服务了。binder 机制支持了嬷嬷和姑娘之间的交互通讯工作。可见binder是一个非常基础的组件

http://www.2cto.com/kf/201209/158014.html

二:下层mediaPlayer 是怎么调到Stagefright的

基于android 4.1.1 源码

【1】mediaserver 启动后会把media相关一些服务添加到servicemanager中,其中就有mediaPlayerService.这样应用启动前,系统就有了mediaPlayerService这个服务程序。   

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

【2】应用层 mediaPlayer调用SDK中 MediaPlayer.java(frameworks\base\media\java\android\media\
下面是MediaPlayer的构造函数:     * Default constructor. Consider using one of the create() methods for     * synchronously instantiating a MediaPlayer from a Uri or resource.     * <p>When done with the MediaPlayer, you should call  {@link #release()},     * to free the resources. If not released, too many MediaPlayer instances may     * result in an exception.</p>     */    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);        mOutOfBandSubtitleTracks = new Vector<SubtitleTrack>();        mOpenSubtitleSources = new Vector<InputStream>();        mInbandSubtitleTracks = new SubtitleTrack[0];        /* 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方式调用到framework层 android_media_MediaPlayer.cpp(\frameworks\base\media\jni\android_media_MediaPlayer.cpp)

static voidandroid_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);}

因为文件开头#include <media/mediaplayer.h>,而MediaPlayer.java在package android.media中;

所以new MediaPlayer()创建的对象是调用mediaplayer.h中的构造函数创建的。

继而调用mediaplayer.cpp(frameworks\av\media\libmedia\mediaplayer.cpp)


【3】在整个应用程序的进程中,mediaplayer.cpp 中 setDataSource会从service manager中获得mediaPlayerService 服务,然后通过服务来创建player。这个player就是播放器的真实实例。

status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source){    ALOGV("setDataSource");    status_t err = UNKNOWN_ERROR;#if MEDIAPLAYER_REUSE    if (mPlayer == NULL) {   const sp<IMediaPlayerService>&service(getMediaPlayerService())//getMediaPlayerService()的作用:establish binder interface to MediaPlayerService
//service是一个指向对象的指针,对象类型是IMediaPlayerService
// const sp<IMediaPlayerService>& service(getMediaPlayerService())等价于:
<span style="font-family: Arial, Helvetica, sans-serif;">// const sp<IMediaPlayerService> temp=getMediaPlayerService();</span>
<span style="font-family: Arial, Helvetica, sans-serif;">// const sp<IMediaPlayerService>& service=temp;</span>
        if (service != 0) {            sp<IMediaPlayer> player(service->create(this, mAudioSessionId));<span style="font-family: Arial, Helvetica, sans-serif;">//player是一个指向对象的指针,对象类型是IMediaPlaye</span>
            if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||                    (NO_ERROR != player->setDataSource(source))) {                player.clear();            }            err =attachNewPlayer(player);        }    } else {        ALOGV("Use the old MediaPlayer");        clear_l();        mCurrentState = MEDIA_PLAYER_INITIALIZED;        err = NO_ERROR;        if ((NO_ERROR != doSetRetransmitEndpoint(mPlayer)) ||                (NO_ERROR != mPlayer->setDataSource(source))) {            err = UNKNOWN_ERROR;            ALOGE("setDataSource error");        }    }#else // #if MEDIAPLAYER_REUSE    const sp<IMediaPlayerService>& service(getMediaPlayerService());    if (service != 0) {        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||            (NO_ERROR != player->setDataSource(source))) {            player.clear();        }        err = attachNewPlayer(player);    }#endif // #if MEDIAPLAYER_REUSE    return err;}
【4】通过 getMediaPlayerService 得到的service其实是 BpMediaPlayerService,这是和mediaPlayerService进程中的BnMediaPlayerService 相对应负责binder通讯。BpMediaPlayerService中的create其实通过binder机制将CREATE消息发送出去。

<pre name="code" class="cpp">    virtual sp<IMediaPlayer> create(            const sp<IMediaPlayerClient>& client, int audioSessionId) {        Parcel data, reply;        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());        data.writeStrongBinder(client->asBinder());        data.writeInt32(audioSessionId);        remote()->transact(CREATE, data, &reply);        return interface_cast<IMediaPlayer>(reply.readStrongBinder());    }
在对面的BnMediaPlayerService中,通过onTransact()来接受这些消息。并把结果返回。

</pre><span style="color:rgb(51,51,51); font-family:Tahoma; font-size:14px; line-height:24px"></span><div style="text-align:left">当发现是CREATE才真正调用了MediaPlayerService 中的create函数。在create函数中其实是创建了一个MediaPlayerService::Client的实例,也就是 说<span style="text-indent:2em; font-family:Arial; line-height:26px; margin:0px; padding:0px; list-style:none outside none; word-break:normal; word-wrap:break-word">MediaPlayerService会为每个client应用进程创建一个相应的MediaPlayerService::Client的实例,来提供服务。</span></div><p style="color:rgb(51,51,51); font-family:Tahoma; font-size:14px; line-height:24px; margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px"></p><p style="color:rgb(51,51,51); font-family:Tahoma; font-size:14px; line-height:24px; margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px"><span style="margin:0px; padding:0px; list-style:none outside none; word-break:normal; word-wrap:break-word; font-family:Arial; line-height:26px"></span></p><pre name="code" class="cpp" style="color: rgb(51, 51, 51); font-family: Tahoma; font-size: 14px; line-height: 24px; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
【5】这样mediaplayer.cpp就得到了一个player的实例,对他来说这个实例和本地的其他类的实例没什么用法上的区别,殊不知其实这个实例是运行在另外一个进程中。实现这种假象的就是binder机制。获得这个实例后继续player->setDataSource().在MediaPlayerService的进程中他的实际函数中,才会真正的创建Stagefright的具体实例。

在上面中已经看不到opencore的影子了,creatPlayer 中会根据类型来创建播放器的实例。Stagefright的实例就是在这里创建的。

下一步我们能真正进入到Stagefright里了



0 0
原创粉丝点击