Android13 NuPlayer::prepareAsync流程分析

首先从NuPlayer的prepareAsync方法开始:

//frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
void NuPlayer::prepareAsync() {
    ALOGV("prepareAsync");


    (new AMessage(kWhatPrepare, this))->post();
}

发送kWhatPrepare消息,消息在onMessageReceived方法中处理:

sp<Source> mSource;
//frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatPrepare:
        {
            ALOGV("onMessageReceived kWhatPrepare");
            mSource->prepareAsync(); //调用Source的prepareAsync方法
            break;
        }
        default:
            TRESPASS();
            break;
    }
}

调用Source的prepareAsync方法:

//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
void NuPlayer::GenericSource::prepareAsync() {
    Mutex::Autolock _l(mLock);
    ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));


    if (mLooper == NULL) {
        mLooper = new ALooper;
        mLooper->setName("generic");
        mLooper->start();


        mLooper->registerHandler(this);
    }


    sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
    msg->post();
}

发送kWhatPrepareAsync消息,消息在onMessageReceived中处理:

//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
    Mutex::Autolock _l(mLock);
    switch (msg->what()) {
      case kWhatPrepareAsync:
      {
          onPrepareAsync();
          break;
      }
      default:
          Source::onMessageReceived(msg);
          break;
    }
}

调用onPrepareAsync方法:

//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
void NuPlayer::GenericSource::onPrepareAsync() {
    mDisconnectLock.lock();
    ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));


    // 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;


            if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
                sp<DataSource> httpSource;
                mDisconnectLock.unlock();
                httpSource = PlayerServiceDataSourceFactory::getInstance()
                        ->CreateMediaHTTP(mHTTPService);
                if (httpSource == NULL) {
                    ALOGE("Failed to create http source!");
                    notifyPreparedAndCleanup(UNKNOWN_ERROR);
                    return;
                }
                mDisconnectLock.lock();


                if (!mDisconnected) {
                    mHttpSource = httpSource;
                }
            }


            mLock.unlock();
            mDisconnectLock.unlock();
            // This might take long time if connection has some issue.
            sp<DataSource> dataSource = PlayerServiceDataSourceFactory::getInstance()
                    ->CreateFromURI(mHTTPService, uri, &mUriHeaders, &contentType,
                            static_cast<HTTPBase *>(mHttpSource.get()));
            mDisconnectLock.lock();
            mLock.lock();
            if (!mDisconnected) {
                mDataSource = dataSource;
            }
        } else {
            if (property_get_bool("media.stagefright.extractremote", true) &&
                    !PlayerServiceFileSource::requiresDrm(
                            mFd.get(), mOffset, mLength, nullptr /* mime */)) {
                sp<IBinder> binder =
                        defaultServiceManager()->getService(String16("media.extractor"));
                if (binder != nullptr) {
                    ALOGD("FileSource remote");
                    sp<IMediaExtractorService> mediaExService(
                            interface_cast<IMediaExtractorService>(binder));
                    sp<IDataSource> source;
                    mediaExService->makeIDataSource(base::unique_fd(dup(mFd.get())), mOffset, mLength, &source);
                    ALOGV("IDataSource(FileSource): %p %d %lld %lld",
                            source.get(), mFd.get(), (long long)mOffset, (long long)mLength);
                    if (source.get() != nullptr) {
                        mDataSource = CreateDataSourceFromIDataSource(source);
                    } else {
                        ALOGW("extractor service cannot make data source");
                    }
                } else {
                    ALOGW("extractor service not running");
                }
            }
            if (mDataSource == nullptr) {
                ALOGD("FileSource local");
                mDataSource = new PlayerServiceFileSource(dup(mFd.get()), mOffset, mLength);
            }
        }


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


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


    mDisconnectLock.unlock();


    // For cached streaming cases, we need to wait for enough
    // buffering before reporting prepared.
    mIsStreaming = (mCachedSource != NULL);


    // init extractor from data source
    status_t err = initFromDataSource(); //初始化解析器,解析器的作用是解析音视频数据


    if (err != OK) {
        ALOGE("Failed to init from data source!");
        notifyPreparedAndCleanup(err);
        return;
    }


    if (mVideoTrack.mSource != NULL) {
        sp<MetaData> meta = getFormatMeta_l(false /* audio */);
        sp<AMessage> msg = new AMessage;
        err = convertMetaDataToMessage(meta, &msg);
        if(err != OK) {
            notifyPreparedAndCleanup(err);
            return;
        }
        notifyVideoSizeChanged(msg); //通知上层Video尺寸变化
    }


    notifyFlagsChanged( /通知上层Flags变化
            // FLAG_SECURE will be known if/when prepareDrm is called by the app
            // FLAG_PROTECTED will be known if/when prepareDrm is called by the app
            FLAG_CAN_PAUSE |
            FLAG_CAN_SEEK_BACKWARD |
            FLAG_CAN_SEEK_FORWARD |
            FLAG_CAN_SEEK);


    finishPrepareAsync(); 


    ALOGV("onPrepareAsync: Done");
}

上面方法的主要处理如下:

1、调用initFromDataSource方法,初始化分离器,分离器的作用是音视频数据分离

2、调用finishPrepareAsync

下面分析进行分析:

NuPlayer::GenericSource::initFromDataSource

//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
status_t NuPlayer::GenericSource::initFromDataSource() {
    sp<IMediaExtractor> extractor;
    sp<DataSource> dataSource;
    {
        Mutex::Autolock _l_d(mDisconnectLock);
        dataSource = mDataSource;
    }
    CHECK(dataSource != NULL);


    mLock.unlock();
    // This might take long time if data source is not reliable.
    extractor = MediaExtractorFactory::Create(dataSource, NULL); //通过MediaExtractorFactory创建MediaExtractor


    if (extractor == NULL) {
        ALOGE("initFromDataSource, cannot create extractor!");
        mLock.lock();
        return UNKNOWN_ERROR;
    }


    sp<MetaData> fileMeta = extractor->getMetaData();


    size_t numtracks = extractor->countTracks();
    if (numtracks == 0) {
        ALOGE("initFromDataSource, source has no track!");
        mLock.lock();
        return UNKNOWN_ERROR;
    }


    mLock.lock();
    mFileMeta = fileMeta;
    if (mFileMeta != NULL) {
        int64_t duration;
        if (mFileMeta->findInt64(kKeyDuration, &duration)) {
            mDurationUs = duration;
        }
    }


    int32_t totalBitrate = 0;


    mMimes.clear();


    for (size_t i = 0; i < numtracks; ++i) {
        sp<IMediaSource> track = extractor->getTrack(i);
        if (track == NULL) {
            continue;
        }


        sp<MetaData> meta = extractor->getTrackMetaData(i);
        if (meta == NULL) {
            ALOGE("no metadata for track %zu", i);
            return UNKNOWN_ERROR;
        }


        const char *mime;
        CHECK(meta->findCString(kKeyMIMEType, &mime));


        ALOGV("initFromDataSource track[%zu]: %s", i, mime);


        // Do the string compare immediately with "mime",
        // we can't assume "mime" would stay valid after another
        // extractor operation, some extractors might modify meta
        // during getTrack() and make it invalid.
        if (!strncasecmp(mime, "audio/", 6)) {
            if (mAudioTrack.mSource == NULL) {
                mAudioTrack.mIndex = i;
                mAudioTrack.mSource = track;
                mAudioTrack.mPackets =
                    new AnotherPacketSource(mAudioTrack.mSource->getFormat());


                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
                    mAudioIsVorbis = true;
                } else {
                    mAudioIsVorbis = false;
                }


                mMimes.add(String8(mime));
            }
        } else if (!strncasecmp(mime, "video/", 6)) {
            if (mVideoTrack.mSource == NULL) {
                mVideoTrack.mIndex = i;
                mVideoTrack.mSource = track;
                mVideoTrack.mPackets =
                    new AnotherPacketSource(mVideoTrack.mSource->getFormat());


                // video always at the beginning
                mMimes.insertAt(String8(mime), 0);
            }
        }


        mSources.push(track);
        int64_t durationUs;
        if (meta->findInt64(kKeyDuration, &durationUs)) {
            if (durationUs > mDurationUs) {
                mDurationUs = durationUs;
            }
        }


        int32_t bitrate;
        if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
            totalBitrate += bitrate;
        } else {
            totalBitrate = -1;
        }
    }


    ALOGV("initFromDataSource mSources.size(): %zu  mIsSecure: %d  mime[0]: %s", mSources.size(),
            mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));


    if (mSources.size() == 0) {
        ALOGE("b/23705695");
        return UNKNOWN_ERROR;
    }


    // Modular DRM: The return value doesn't affect source initialization.
    (void)checkDrmInfo();


    mBitrate = totalBitrate;


    return OK;
}

上面方法主要处理如下:

1、调用MediaExtractorFactory::Create,通过MediaExtractorFactory创建MediaExtractor

2、通过MediaExtractor的getMetaData方法取得MetaData

3、调用MediaExtractor的countTracks方法

4、调用MediaExtractor的getTrack方法取得track

MediaExtractor相关的内容会在MediaExtractor中介绍。

NuPlayer::GenericSource::finishPrepareAsync

//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
void NuPlayer::GenericSource::finishPrepareAsync() {
    ALOGV("finishPrepareAsync");


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


    if (mIsStreaming) {
        mCachedSource->resumeFetchingIfNecessary();
        mPreparing = true;
        schedulePollBuffering();
    } else {
        notifyPrepared();
    }


    if (mAudioTrack.mSource != NULL) {
        postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
    }


    if (mVideoTrack.mSource != NULL) {
        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
    }
}

NuPlayer::GenericSource::startSources

调用startSources方法:

struct Track {
    size_t mIndex;
    sp<IMediaSource> mSource;
    sp<AnotherPacketSource> mPackets;
};
Track mAudioTrack;
Track mVideoTrack;
//frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp
status_t NuPlayer::GenericSource::startSources() {
    // Start the selected A/V tracks now before we start buffering.
    // Widevine sources might re-initialize crypto when starting, if we delay
    // this to start(), all data buffered during prepare would be wasted.
    // (We don't actually start reading until start().)
    //
    // TODO: this logic may no longer be relevant after the removal of widevine
    // support
    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;
}

调用IMediaSource的start方法:

//frameworks/av/media/libmedia/IMediaSource.cpp
class BpMediaSource : public BpInterface<IMediaSource> {
public:
    explicit BpMediaSource(const sp<IBinder>& impl)
        : BpInterface<IMediaSource>(impl), mBuffersSinceStop(0)
    {
    }


    virtual status_t start(MetaData *params) {
        ALOGV("start");
        Parcel data, reply;
        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
        if (params) {
            params->writeToParcel(data);
        }
        status_t ret = remote()->transact(START, data, &reply);
        if (ret == NO_ERROR && params) {
            ALOGW("ignoring potentially modified MetaData from start");
            ALOGW("input:");
            params->dumpToLog();
            sp<MetaData> meta = MetaData::createFromParcel(reply);
            ALOGW("output:");
            meta->dumpToLog();
        }
        return ret;
    }
}

调用remote()->transact(START, data, &reply)方法,在onTransact中处理:

//frameworks/av/media/libmedia/IMediaSource.cpp
status_t BnMediaSource::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
        case START: {
            ALOGV("start");
            CHECK_INTERFACE(IMediaSource, data, reply);
            sp<MetaData> meta;
            if (data.dataAvail()) {
                meta = MetaData::createFromParcel(data);
            }
            status_t ret = start(meta.get());
            if (ret == NO_ERROR && meta != NULL) {
                meta->writeToParcel(*reply);
            }
            return ret;
        }
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

RemoteMediaSource::start

调用start方法,start方法由BnMediaSource的子类RemoteMediaSource实现:

MediaTrack *mTrack;
//frameworks/av/media/libstagefright/RemoteMediaSource.cpp
status_t RemoteMediaSource::start(MetaData *params) {
    if (params) {
        ALOGW("dropping start parameters:");
        params->dumpToLog();
    }
    return mTrack->start();
}

调用MediaTrack的start方法,MediaTrackCUnwrapper继承于MediaTrack,因此调用MediaTrackCUnwrapper的start方法:

CMediaTrack *wrapper;
//frameworks/av/media/libstagefright/MediaTrack.cpp
status_t MediaTrackCUnwrapper::start() {
    if (bufferGroup == nullptr) {
        bufferGroup = new MediaBufferGroup(); //创建MediaBufferGroup对象
    }
    return reverse_translate_error(wrapper->start(wrapper->data, bufferGroup->wrap())); //调用CMediaTrack的start方法
}

调用CMediaTrack的start方法,CMediaTrack是一个结构体,定义在MediaExtractorPluginApi.h中:

//frameworks/av/include/media/MediaExtractorPluginApi.h
struct CMediaTrack {
    void *data;
    void (*free)(void *data);


    media_status_t (*start)(void *data, CMediaBufferGroup *bufferGroup);
    media_status_t (*stop)(void *data);
    media_status_t (*getFormat)(void *data, AMediaFormat *format);
    media_status_t (*read)(void *data, CMediaBuffer **buffer, uint32_t options, int64_t seekPosUs);
    bool     (*supportsNonBlockingRead)(void *data);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值