Android多媒体播放器源码解析(stagefright框架)

一、android多媒体播放的调用步骤:

a) android中定义一个MediaPlayer类

b) 在MediaPlayer中使用JNI技术调用的是android_media_MediaPlayer.cpp(media\jni,在这个类中对标准的JNI函数名称进行的转换)

c) 以下涉及的都是C++,android_media_MediaPlayer中调用的是mediaplayer.cpp(media\libmedia,涉及的库libmedia.so)中的函数

d) 然后调用MediaPlayerService.cpp(media\libmediaplayerservice)中的函数

e) 之后开始选择是使用OpenCore还是Stagefright(2.3中使用的是Stagefright),因此接下来调用的是StagefrightPlayer.cpp(media\libmediaplayerservice)中的相关函数

f) 接下去就到了最关键的一个类AwesomePlayer.cpp(media\libstagefright),在这个类里面我们要对read进的buffer进行一些相应的处理,然后再render渲染到surface(这边涉及的库可能是libStagefright.so)

二、以setDataSource()来分析android多媒体播放过程:

a) MediaPlayer类有setDataSource方法,查看源码,它最后调用的是一个native函数(JNI标准),public native void setDataSource(String path),这个函数在android_media_MediaPlayer.cpp中实现

b) android_media_MediaPlayer.cpp中

android_media_MediaPlayer_setDataSourceAndHeaders(

        JNIEnv *env, jobject thiz, jstring path, jobject headers)

sp<MediaPlayer> mp = getMediaPlayer(env, thiz);

。。。

status_t opStatus = mp->setDataSource(String8(pathStr), headers ? &headersVector : NULL);

。。。

其中mp是一个MediaPlayer的实例对象,pathStr是视频路径,之后会进入到 mediaplayer.cpp中的 setDataSource()函数

c) Mediaplayer.cpp中

status_t MediaPlayer::setDataSource(

        const char *url, const KeyedVector<String8, String8> *headers)

{

    LOGV("setDataSource(%s)", url);

    status_t err = BAD_VALUE;

    if (url != NULL) {

        const sp<IMediaPlayerService>& service(getMediaPlayerService());

        if (service != 0) {

            sp<IMediaPlayer> player(

                    service->create(getpid(), this, url, headers, mAudioSessionId));

            err = setDataSource(player);

        }

    }

    return err;

}

这里会调用service的create()函数

d) 在MediaPlayerService.cpp中

sp<IMediaPlayer> MediaPlayerService::create(

        pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,

        const KeyedVector<String8, String8> *headers, int audioSessionId)

{

    int32_t connId = android_atomic_inc(&mNextConnId);

    sp<Client> c = new Client(this, pid, connId, client, audioSessionId);

    LOGV("Create new client(%d) from pid %d, url=%s, connId=%d, audioSessionId=%d",

            connId, pid, url, connId, audioSessionId);

    if (NO_ERROR != c->setDataSource(url, headers))

    {

        c.clear();

        return c;

    }

    wp<Client> w = c;

    Mutex::Autolock lock(mLock);

    mClients.add(w);

    return c;

}

其中调用了Client类的setDataSource()函数,这个Client比较难找,其实它 是在MediaPlayerService.h中定义的,在java中叫内部类,C++中忘了,查看 Client类中的setDataSource()函数的代码

status_t MediaPlayerService::Client::setDataSource(

        const char *url, const KeyedVector<String8, String8> *headers)

{

    LOGV("setDataSource(%s)", url);

    if (url == NULL)

        return UNKNOWN_ERROR;

    if (strncmp(url, "content://", 10) == 0) {

        // get a filedescriptor for the content Uri and

        // pass it to the setDataSource(fd) method

        String16 url16(url);

        int fd = android::openContentProviderFile(url16);

        if (fd < 0)

        {

            LOGE("Couldn't open fd for %s", url);

            return UNKNOWN_ERROR;

        }

        setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus

        close(fd);

        return mStatus;

    } else {

        player_type playerType = getPlayerType(url);

        LOGV("player type = %d", playerType);

        // create the right type of player

        sp<MediaPlayerBase> p = createPlayer(playerType);

        if (p == NULL) return NO_INIT;

        if (!p->hardwareOutput()) {

            mAudioOutput = new AudioOutput(mAudioSessionId);

            static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);

        }

        // now set data source

        LOGV(" setDataSource");

        mStatus = p->setDataSource(url, headers);

        if (mStatus == NO_ERROR) {

            mPlayer = p;

        } else {

            LOGE("  error: %d", mStatus);

        }

        return mStatus;

    }

}

其中定义了一个MediaPlayerBase类的实例对象p,并且接下去调用了p的 setDataSource()函数,我们先看看createPlayer()这个函数的源码

static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,

        notify_callback_f notifyFunc)

{

    sp<MediaPlayerBase> p;

    switch (playerType) {

#ifndef NO_OPENCORE

        case PV_PLAYER:

            LOGV(" create PVPlayer");

            p = new PVPlayer();

            break;

#endif

        case SONIVOX_PLAYER:

            LOGV(" create MidiFile");

            p = new MidiFile();

            break;

        case STAGEFRIGHT_PLAYER:

            LOGV(" create StagefrightPlayer");

            p = new StagefrightPlayer;

            break;

        case TEST_PLAYER:

            LOGV("Create Test Player stub");

            p = new TestPlayerStub();

            break;

    }

    if (p != NULL) {

        if (p->initCheck() == NO_ERROR) {

            p->setNotifyCallback(cookie, notifyFunc);

        } else {

            p.clear();

        }

    }

    if (p == NULL) {

        LOGE("Failed to create player object");

    }

    return p;

}

值得注意的是红色部分,这边就到了StagefrightPlayer.cpp,上面说到定义了一 个MediaPlayerBase类的实例对象p,并且接下去调用了p的 setDataSource() 函数,那么我们就理所当然地去找MediaPlayerBase类了,但是找了很久没找到, 现在知道了,上面红色部分将new出来的StagefrightPlayer对象赋给了P,那么 P调 用的setDataSource()事实上是StagefrightPlayer这个类中的 setDataSource()这个函数

e) 在StagefrightPlayer.cpp中

status_t StagefrightPlayer::setDataSource(

        const char *url, const KeyedVector<String8, String8> *headers) {

    LOGI("setDataSource('%s')", url);

    return mPlayer->setDataSource(url, headers);

}

其中,直接调用mPlayer->setDataSource(url, headers),那么这个mPlayer是什么 呢?在上一个步骤中的new StagefrightPlayer中其实已经赋值了,源码如下

StagefrightPlayer::StagefrightPlayer()

    : mPlayer(new AwesomePlayer) {

    LOGV("StagefrightPlayer");

    mPlayer->setListener(this);

}

从红色部分可以看出mPlayer是一个AwesomePlayer类的实例对象,那么这个 setDataSource()函数自然就到这个类中去找了

f) 在AwesomePlayer.cpp中

void AwesomePlayer::onVideoEvent() {

。。。。。。

for (;;) {

。。。。。。

            status_t err = mVideoSource->read(&mVideoBuffer, &options);

            options.clearSeekTo();

。。。。。。

。。。。。。

    if (mVideoRenderer != NULL) {

        mVideoRenderer->render(mVideoBuffer);

}

。。。。。。

}

第一行红色字表示将帧数据读入mVideoBuffer,第二行红色字体是将这些帧数据渲染到画布中。我们需要修改的就是这个部分,不往下分析了。

三、以start()来分析android多媒体播放过程

a) 首先查看MediaPlayer.java这个类的源码

public  void start() throws IllegalStateException {

        stayAwake(true);

        _start();

}

之后调用的是_start()这个native函数(JNI标准),即private native void _start() throws IllegalStateException这个函数在android_media_MediaPlayer.cpp中实现

b) 在Android_media_MediaPlayer.cpp中

static void

android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)

{

    LOGV("start");

    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);

    if (mp == NULL ) {

        jniThrowException(env, "java/lang/IllegalStateException", NULL);

        return;

    }

    process_media_player_call( env, thiz, mp->start(), NULL, NULL );

}

我们看红色部分的代码,最终调用的是mp->start(),这个mp其实是MediaPlayer的一个对象,那么我们就去MediaPlayer.cpp中查看源码

c) 在MediaPlayer.cpp中

status_t MediaPlayer::start()

{

。。。。。。

        mCurrentState = MEDIA_PLAYER_STARTED;

        status_t ret = mPlayer->start();

        if (ret != NO_ERROR) {

            mCurrentState = MEDIA_PLAYER_STATE_ERROR;

        } else {

        。。。。。。

}
这时候调用了mPlayer的start()这个函数,查看MediaPlayer.h中,可以发现sp<IMediaPlayer> mPlayer,那么再去IMediaPlayer.cpp中去看看

d) 在IMediaPlayer.cpp中

status_t start()

    {

        Parcel data, reply;

        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

        remote()->transact(START, data, &reply);

        return reply.readInt32();

    }

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值