android多媒体开发笔记

一:上层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 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);
}

因为文件开头#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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值