8. Android MultiMedia框架完全解析 - prepareAsync的过程分析

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

还是从mediaplayer.cpp文件开始分析:

status_t MediaPlayer::prepareAsync()
{
    ALOGV("prepareAsync");
    Mutex::Autolock _l(mLock);
    return prepareAsync_l();
}

基本没做什么,设置了一个自动锁,然后就直接跳到MediaPlayer::prepareAsync_l中去执行了:

status_t MediaPlayer::prepareAsync_l()
{
    if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
        if (mAudioAttributesParcel != NULL) {
            mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
        } else {
            mPlayer->setAudioStreamType(mStreamType);
        }
        mCurrentState = MEDIA_PLAYER_PREPARING;
        return mPlayer->prepareAsync();
    }
    ALOGE("prepareAsync called in state %d", mCurrentState);
    return INVALID_OPERATION;
}

这里有两个函数要执行,第一个函数:setAudioStreamType,这里的mPlayer是IMediaPlayer这个匿名Binder Server,会通过IMediaPlayer最终调用到MediaPlayerService::Client::setAudioStreamType函数:

status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type)
{
    ALOGV("[%d] setAudioStreamType(%d)", mConnId, type);
    // TODO: for hardware output, call player instead
    Mutex::Autolock l(mLock);
    if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
    return NO_ERROR;
}

之后就是prepareAsync函数,同样是通过IMediaPlayer最终调用到MediaPlayerService::Client::prepareAsync函数:

status_t MediaPlayerService::Client::prepareAsync()
{
    ALOGV("[%d] prepareAsync", mConnId);
    sp<MediaPlayerBase> p = getPlayer();
    if (p == 0) return UNKNOWN_ERROR;
    status_t ret = p->prepareAsync();

    return ret;
}

在之前的分析中说过,这里的p得到的是NuPlayerDriver,然后就是调用

status_t NuPlayerDriver::prepareAsync() {
    ALOGV("prepareAsync(%p)", this);
    Mutex::Autolock autoLock(mLock);

    switch (mState) {
        case STATE_UNPREPARED:
            mState = STATE_PREPARING;
            mIsAsyncPrepare = true;
            mPlayer->prepareAsync();
            return OK;
        case STATE_STOPPED:
            // this is really just paused. handle as seek to start
            mAtEOS = false;
            mState = STATE_STOPPED_AND_PREPARING;
            mIsAsyncPrepare = true;
            mPlayer->seekToAsync(0, true /* needNotify */);
            return OK;
        default:
            return INVALID_OPERATION;
    };
}

NuPlayerDriver根据mState的状态来选择执行哪一个分支,刚执行到这里,当前的状态一般是STATE_UNPREPARED,所以会执行 mPlayer->prepareAsync(),而在NuPlayerDriver中的mPlayer是NuPlayer,所以就会调用到NuPlayer的prepareAsync函数,而这个函数的实现更为简单:

void NuPlayer::prepareAsync() {
    (new AMessage(kWhatPrepare, this))->post();
}

继续查找NuPlayer::onMessageReceived函数中的实现:

case kWhatPrepare:
        {
            mSource->prepareAsync();
            break;
        }

发现就直接调用到mSource里面的函数了,这个mSource在setDataSource函数中设置了,为GenericSource,那么继续向下看:

这个NuPlayer::GenericSource继承自NuPlayer::Source,而NuPlayer::Source又继承自AHandler,所以在GenericSource中也可以使用AHandler-Amessage-ALooper机制,在这个函数中创建了ALooper,并且设置Looper的Handler为这个GenericSource,然后发送kWhatPrepareAsync这个AMessage来交给onMessageReceived函数来运行,最终运行到NuPlayer::GenericSource::onPrepareAsync函数中(GenericSource.cpp):

void NuPlayer::GenericSource::onPrepareAsync() {
    // delayed data source creation
    if (mDataSource == NULL) {
        // set to false first, if the extractor
        // comes back as secure, set it to true then.
        mIsSecure = false;

        if (!mUri.empty()) {
            const char* uri = mUri.c_str();
            String8 contentType;
            mIsWidevine = !strncasecmp(uri, "widevine://", 11);

            if (!strncasecmp("http://", uri, 7)
                    || !strncasecmp("https://", uri, 8)
                    || mIsWidevine) {
                mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
                if (mHttpSource == NULL) {
                    ALOGE("Failed to create http source!");
                    notifyPreparedAndCleanup(UNKNOWN_ERROR);
                    return;
                }
            }

            mDataSource = DataSource::CreateFromURI(
                   mHTTPService, uri, &mUriHeaders, &contentType,
                   static_cast<HTTPBase *>(mHttpSource.get()));
        } else {
            mIsWidevine = false;
            mDataSource = new FileSource(mFd, mOffset, mLength);
            mFd = -1;
        }

        if (mDataSource == NULL) {
            ALOGE("Failed to create data source!");
            notifyPreparedAndCleanup(UNKNOWN_ERROR);
            return;
        }
    }

    if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
        mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
    }

    // For widevine or other cached streaming cases, we need to wait for
    // enough buffering before reporting prepared.
    // Note that even when URL doesn't start with widevine://, mIsWidevine
    // could still be set to true later, if the streaming or file source
    // is sniffed to be widevine. We don't want to buffer for file source
    // in that case, so must check the flag now.
    mIsStreaming = (mIsWidevine || mCachedSource != NULL);

    // init extractor from data source
    status_t err = initFromDataSource();
    
    先截取到这里,后面的代码分析到了再放出来。
}

这个函数挺长的,一点一点分析。

在函数的开始,还没有对mDataSource赋值,同时!mUri.empty() = 0, 所以会走到

mDataSource = new FileSource(mFd, mOffset, mLength);这个分支。

这里又出来一个DataSource,同时

class FileSource : public DataSource

struct NuCachedSource2 : public DataSource

class DataSource是抽象出来的一个Source父类,不同的Source都是这个类的子类。

下一个重要的函数就是initFromDataSource了,这个函数的注释是:init extractor from data source,函数是:NuPlayer::GenericSource::initFromDataSource()

在这个函数中,首先对mIsWidevine,mIsStreaming进行判断,在上层的NuPlayer::GenericSource::onPrepareAsync函数中,对于普通的FileSource,都设置这两者为Null,这两者是与Widevine和实时视频流相关的,所以走到MediaExtractor的创建阶段:

extractor = MediaExtractor::Create(mDataSource,

mimeType.isEmpty() ? NULL : mimeType.string());

会根据DataSource的类型来创建对应的Extractor。具体MediaExtractor::Create函数的执行过程在《10. MediaExtractor::Create函数的解析和FslExtractor分析》中详细介绍了,它通过sniff函数检测出媒体类型,然后创建出对应Extractor,而对于FSL的平台,创建出来的就是FslExtractor,创建好以后,就可以开始解析文件内容了。

mFileMeta = extractor->getMetaData();

继续看《10. MediaExtractor::Create函数的解析和FslExtractor分析--- 三》

继续回到NuPlayer::GenericSource::initFromDataSource()函数中,执行完extractor->getMetaData()后,我们也就知道了文件中所包含的track数和里面的数据,打印出下面的话:

GenericSource: mFileMeta = 1.

说明mFileMeta数据不为空,这时候就通过mFileMeta->findInt64(kKeyDuration, &duration)来获取文件的Duration数据。

然后通过extractor->countTracks()来统计文件中Track的数目,可以看到FslExtractor::countTracks()函数的实现:

size_t FslExtractor::countTracks()
{
    status_t ret = OK;
    if(!bInit){
        ret = Init();

        if(ret != OK)
            return 0;
    }

    return mTracks.size();
}

发现这个函数里面,只是判断Init函数有没有执行,因为countTracks这些操作都是在Init函数中做的。

然后通过一个for循环来遍历这些tracks,将从Extractor中解析出来的metadata等等数据,保存在GenericSource结构体中的MVideoTrack和mAudioTrack中。

终于分析完initFromDataSource函数了,下面继续跳回NuPlayer::GenericSource::onPrepareAsync()函数中。。。。

void NuPlayer::GenericSource::onPrepareAsync() {
。。。。。。。。。
继续上面的代码,从initFromDataSource()后面开始

off64_t size;
    if(mCachedSource != NULL && mCachedSource->getSize(&size) == OK && mDurationUs > 0){
        ALOGV("file size is %lld, duration is %lld", size, mDurationUs);
        int64_t bitrate = size * 8000000ll / mDurationUs;
        // When bitrate is larger than 15Mbps, use calculated watermarks.
        if(bitrate > 15 * 1024 * 1024){
            size_t lowWaterMark = bitrate / 8 * (kLowWaterMarkUs / 1000000 + 3) ;
            size_t highWaterMark = bitrate / 8 * (kHighWaterMarkUs / 1000000 + 3);
            ALOGI("bitrate is %lld, set new cache watermark to %d - %d", bitrate, lowWaterMark, highWaterMark);
            char s[30];
            sprintf(s,"%zd/%zd/%d", lowWaterMark/1000, highWaterMark/1000, -1);
            mCachedSource->updateCacheParamsFromString(s);
        }
    }

    if (err != OK) {
        ALOGE("Failed to init from data source!");
        notifyPreparedAndCleanup(err);
        return;
    }
//上面这段代码应该不会执行。

    if (mVideoTrack.mSource != NULL) {
        sp<MetaData> meta = doGetFormatMeta(false /* audio */);
        sp<AMessage> msg = new AMessage;
        err = convertMetaDataToMessage(meta, &msg);
        if(err != OK) {
            notifyPreparedAndCleanup(err);
            return;
        }
        notifyVideoSizeChanged(msg);
    }

    uint32_t flags =
        (mIsSecure ? FLAG_SECURE : 0)
        | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
        | FLAG_CAN_PAUSE ;

    uint32_t extractor_flags = mExtractor->flags();
    if(extractor_flags & MediaExtractor::CAN_SEEK)
        flags |= FLAG_CAN_SEEK;
    if(extractor_flags & MediaExtractor::CAN_SEEK_FORWARD)
        flags |= FLAG_CAN_SEEK_FORWARD;
    if(extractor_flags & MediaExtractor::CAN_SEEK_BACKWARD)
        flags |= FLAG_CAN_SEEK_BACKWARD;

    ALOGV("flags %x", flags);

    notifyFlagsChanged(flags);

    if (mIsSecure) {
        // secure decoders must be instantiated before starting widevine source
        sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
        notifyInstantiateSecureDecoders(reply);
    } else {
        finishPrepareAsync();
    }
}

在doGetFormatMeta函数内部,通过source->getFormat()来获取到Track中的format,然后调用到notifyVideoSizeChanged函数,这个函数是NuPlayer::Source里面的函数:

NuPlayer::Source::notifyVideoSizeChanged,这时候已经跳转到NuPlayer.cpp中执行了,最后执行到updateVideoSize里面,打印出:

NuPlayer: Video input format 1024 x 768

同时在这个函数的最后,执行:

notifyListener(
            MEDIA_SET_VIDEO_SIZE,
            displayWidth,
            displayHeight);

把设置的Video的width和height通知出来,通过下面的函数跳到NuPlayerDriver中:

void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) {
    if (mDriver == NULL) {
        return;
    }

    sp<NuPlayerDriver> driver = mDriver.promote();

    if (driver == NULL) {
        return;
    }

    driver->notifyListener(msg, ext1, ext2, in);
}

void NuPlayerDriver::notifyListener(
        int msg, int ext1, int ext2, const Parcel *in) {
    Mutex::Autolock autoLock(mLock);
    notifyListener_l(msg, ext1, ext2, in);
}

在NuPlayerDriver::notifyListener_l函数中,只是对MEDIA_PLAYBACK_COMPLETE和MEDIA_ERROR进行了处理,并没有对MEDIA_SET_VIDEO_SIZE进行处理,所以执行默认的default操作,然后通过 sendEvent(msg, ext1, ext2, in);NuPlayerDriver的上一层时MediaPlayerService,所以这时候就到达了MediaPlayerService::Client::notify函数中,打印出:

MediaPlayerService: [1] notify (0xb3ee73c0, 5, 1024, 768)

这句话。

打印后,执行c->notify(msg, ext1, ext2, obj);,这时候位于MediaPlayerService.cpp中,所以执行这个notify是IMediaPlayerClient,到达IMediaPlayerClient的Bp端,再传递到Bn端。

class MediaPlayer : public BnMediaPlayerClient,

public virtual IMediaDeathNotifier

所以Bn端的代码会传递到MediaPlayer类中,然后就在MediaPlayer::notify函数中(mediaplayer.cpp)进行处理。这个notify的传递过程与现在探讨的函数传递方向相反。正常是mediaplayer.cpp--->MediaPlayerService--->NuPlayerDriver--->NuPlayer

这个方向是相反的:NuPlayer--->NuPlayerDriver--->MeidaPlayerService--->mediaplayer.cpp

然后MediaPlayer::notify函数打印出接收到的msg:

MediaPlayer: message received msg=5, ext1=1024, ext2=768

然后处理这个msg,打印出下面的话:

ALOGV("New video size %d x %d", ext1, ext2);

继续在NuPlayer::GenericSource::onPrepareAsync()函数中运行:

从mExtractor中获取文件的flag参数,这些参数包括:FLAG_CAN_PAUSE,FLAG_CAN_SEEK_BACKWARD,FLAG_CAN_SEEK_FORWARD,FLAG_CAN_SEEK,FLAG_DYNAMIC_DURATION等等。最终打印出来的是这些位按位与的结果,比如这个文件可以执行的操作flag就是:f。

最后,还有一个很重要的知识点,就是最后有个finishPrepareAsync()函数,看看上面的NuPlayer::GenericSource::finishPrepareAsync()函数中的表述:

if (mIsSecure) {
        // secure decoders must be instantiated before starting widevine source
        sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
        notifyInstantiateSecureDecoders(reply);
    } else {
        finishPrepareAsync();
    }

如果是secure decoders的话,就需要在这里通过notifyInstantiateSecureDecoders函数来初始化Decoder,但是目前播放的是普通的MP4文件,所以会调用下面的finishPrepareAsync函数,这个函数一不小心就漏掉了:

void NuPlayer::GenericSource::finishPrepareAsync() {
    status_t err = startSources();
    if (err != OK) {
        ALOGE("Failed to init start data source!");
        notifyPreparedAndCleanup(err);
        return;
    }

    if (mIsStreaming) {
        mPrepareBuffering = true;

        ensureCacheIsFetching();
        restartPollBuffering();
    } else {
        notifyPrepared();
    }
}

就是我标记红色的代码,也很容易遗漏,先看第一段代码(startSources()):

status_t NuPlayer::GenericSource::startSources() {
   if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
        ALOGE("failed to start audio track!");
        return UNKNOWN_ERROR;
    }

    if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
        ALOGE("failed to start video track!");
        return UNKNOWN_ERROR;
    }

    return OK;
}

这个函数让Track的source开始运行,由于这个文件中只有VideoTrack,所以执行 mVideoTrack.mSource->start(),跳到FslMediaSource::start函数中(FslExtractor.cpp):

status_t FslMediaSource::start(MetaData * /* params */)
{
    mStarted = true;
    mExtractor->ActiveTrack(mSourceIndex);
    ALOGD("source start track %d",mSourceIndex);
    return OK;
}

继续追踪(FslExtractor.cpp):

status_t FslExtractor::ActiveTrack(uint32 index)
{
    uint64 seekPos = 0;
    Mutex::Autolock autoLock(mLock);
    bool seek = true;

    TrackInfo *trackInfo = &mTracks.editItemAt(index);
    if(trackInfo == NULL)
        return UNKNOWN_ERROR;
    trackInfo->bCodecInfoSent = false;
    if(trackInfo->type == MEDIA_VIDEO){
        seekPos = currentVideoTs;
        mVideoActived = true;
    }else if(trackInfo->type == MEDIA_AUDIO)
        seekPos = currentAudioTs;
    else if(currentVideoTs > 0)
        seekPos = currentVideoTs;
    else
        seekPos = currentAudioTs;

    IParser->enableTrack(parserHandle,trackInfo->mTrackNum, TRUE);

    if(trackInfo->type == MEDIA_TEXT || trackInfo->type == MEDIA_AUDIO){
        if(isTrackModeParser())
            seek = true;
        else
            seek = false;
    }

    if(seek)
        IParser->seek(parserHandle, trackInfo->mTrackNum, &seekPos, SEEK_FLAG_NO_LATER);

    ALOGD("start track %d",trackInfo->mTrackNum);
    return OK;
}

核心是IParser->enableTrack(parserHandle,trackInfo->mTrackNum, TRUE);函数,还是lib库中提供的接口。

然后看标红的第二段代码(notifyPrepared()):

跳转到NuPlayer::Source::notifyPrepared中去执行了:

void NuPlayer::Source::notifyPrepared(status_t err) {
    sp<AMessage> notify = dupNotify();
    notify->setInt32("what", kWhatPrepared);
    notify->setInt32("err", err);
    notify->post();
}

发送消息,到NuPlayer::onSourceNotify中去执行,最终是找到NuPlayerDriver:

driver->notifyPrepareCompleted(err);

继续跳转:

void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
    Mutex::Autolock autoLock(mLock);

    if (mState != STATE_PREPARING) {
        // We were preparing asynchronously when the client called
        // reset(), we sent a premature "prepared" notification and
        // then initiated the reset. This notification is stale.
        CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
        return;
    }

    CHECK_EQ(mState, STATE_PREPARING);

    mAsyncResult = err;

    if (err == OK) {
        // update state before notifying client, so that if client calls back into NuPlayerDriver
        // in response, NuPlayerDriver has the right state
        mState = STATE_PREPARED;
        if (mIsAsyncPrepare) {
            notifyListener_l(MEDIA_PREPARED);
        }
    } else {
        mState = STATE_UNPREPARED;
        if (mIsAsyncPrepare) {
            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
        }
    }

    sp<MetaData> meta = mPlayer->getFileMeta();
    int32_t loop;
    if (meta != NULL
            && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
        mAutoLoop = true;
    }

    mCondition.broadcast();
}

这里notifyListener_l(MEDIA_PREPARED)直接调用到NuPlayerDriver::notifyListener_l()函数,

然后同样通过IMediaPlayerClient的Bp端传到Bn端,再传递到mediaplayer.cpp中。

至此,这个函数的执行流程才算分析完毕。

猜你喜欢

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