Android13 HTTPLiveSource代码分析

HTTPLiveSource主要用户解析HLS协议,如下为HTTPLiveSource的结构图:

当调用HTTPLiveSource的prepareAsync函数时,代码如下:

//frameworks/av/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
void NuPlayer::HTTPLiveSource::prepareAsync() {
    if (mLiveLooper == NULL) {
        mLiveLooper = new ALooper;
        mLiveLooper->setName("http live");
        mLiveLooper->start();


        mLiveLooper->registerHandler(this);
    }


    sp<AMessage> notify = new AMessage(kWhatSessionNotify, this);


    mLiveSession = new LiveSession(
            notify,
            (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
            mHTTPService); //构建了一个LiveSession对象


    mLiveLooper->registerHandler(mLiveSession);


    mLiveSession->setBufferingSettings(mBufferingSettings);
    mLiveSession->connectAsync(
            mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); //创建一个会话
}

内部主要构建了一个LiveSession对象。通过LiveSession内部的connectAsync函数,创建一个会话:

//frameworks/av/media/libstagefright/httplive/LiveSession.cpp
void LiveSession::connectAsync(
        const char *url, const KeyedVector<String8, String8> *headers) {
    sp<AMessage> msg = new AMessage(kWhatConnect, this);
    msg->setString("url", url);


    if (headers != NULL) {
        msg->setPointer(
                "headers",
                new KeyedVector<String8, String8>(*headers));
    }


    msg->post(); //发送kWhatConnect消息
}

发送kWhatConnect消息,发送的消息在onMessageReceived中处理:

//frameworks/av/media/libstagefright/httplive/LiveSession.cpp
void LiveSession::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatConnect:
        {
            onConnect(msg);
            break;
        }
}

接下来看看onConnect方法:

//frameworks/av/media/libstagefright/httplive/LiveSession.cpp
void LiveSession::onConnect(const sp<AMessage> &msg) {
    CHECK(msg->findString("url", &mMasterURL));


    // TODO currently we don't know if we are coming here from incognito mode
    ALOGI("onConnect %s", uriDebugString(mMasterURL).c_str());


    KeyedVector<String8, String8> *headers = NULL;
    if (!msg->findPointer("headers", (void **)&headers)) {
        mExtraHeaders.clear();
    } else {
        mExtraHeaders = *headers;


        delete headers;
        headers = NULL;
    }


    // create looper for fetchers
    if (mFetcherLooper == NULL) {
        mFetcherLooper = new ALooper(); //创建一个轮询器


        mFetcherLooper->setName("Fetcher");
        mFetcherLooper->start(false, /* runOnCallingThread */
                              true  /* canCallJava */);
    }


    // create fetcher to fetch the master playlist
    addFetcher(mMasterURL.c_str())->fetchPlaylistAsync(); //创建获取器取播放列表
}

网络请求,开始取播放列。在取到播放列表后,会进行回调:

//frameworks/av/media/libstagefright/httplive/LiveSession.cpp
void LiveSession::onMasterPlaylistFetched(const sp<AMessage> &msg) {
    AString uri;
    CHECK(msg->findString("uri", &uri));
    ssize_t index = mFetcherInfos.indexOfKey(uri);
    if (index < 0) {
        ALOGW("fetcher for master playlist is gone.");
        return;
    }


    // no longer useful, remove
    mFetcherLooper->unregisterHandler(mFetcherInfos[index].mFetcher->id());
    mFetcherInfos.removeItemsAt(index);


    CHECK(msg->findObject("playlist", (sp<RefBase> *)&mPlaylist));
    if (mPlaylist == NULL) {
        ALOGE("unable to fetch master playlist %s.",
                uriDebugString(mMasterURL).c_str());


        postPrepared(ERROR_IO);
        return;
    }
    // We trust the content provider to make a reasonable choice of preferred
    // initial bandwidth by listing it first in the variant playlist.
    // At startup we really don't have a good estimate on the available
    // network bandwidth since we haven't tranferred any data yet. Once
    // we have we can make a better informed choice.
    size_t initialBandwidth = 0;
    size_t initialBandwidthIndex = 0;


    int32_t maxWidth = 0;
    int32_t maxHeight = 0;


    if (mPlaylist->isVariantPlaylist()) { //判断是否有效的播放列表
        Vector<BandwidthItem> itemsWithVideo;
        for (size_t i = 0; i < mPlaylist->size(); ++i) {
            BandwidthItem item;


            item.mPlaylistIndex = i;
            item.mLastFailureUs = -1LL;


            sp<AMessage> meta;
            AString uri;
            mPlaylist->itemAt(i, &uri, &meta);


            CHECK(meta->findInt32("bandwidth", (int32_t *)&item.mBandwidth));


            int32_t width, height;
            if (meta->findInt32("width", &width)) {
                maxWidth = max(maxWidth, width);
            }
            if (meta->findInt32("height", &height)) {
                maxHeight = max(maxHeight, height);
            }


            mBandwidthItems.push(item); //存储到容器中
            if (mPlaylist->hasType(i, "video")) {
                itemsWithVideo.push(item);
            }
        }
        // remove the audio-only variants if we have at least one with video
        if (!itemsWithVideo.empty()
                && itemsWithVideo.size() < mBandwidthItems.size()) {
            mBandwidthItems.clear();
            for (size_t i = 0; i < itemsWithVideo.size(); ++i) {
                mBandwidthItems.push(itemsWithVideo[i]);
            }
        }


        CHECK_GT(mBandwidthItems.size(), 0u);
        initialBandwidth = mBandwidthItems[0].mBandwidth;


        mBandwidthItems.sort(SortByBandwidth);


        for (size_t i = 0; i < mBandwidthItems.size(); ++i) {
            if (mBandwidthItems.itemAt(i).mBandwidth == initialBandwidth) {
                initialBandwidthIndex = i;
                break;
            }
        }
    } else {
        // dummy item.
        BandwidthItem item;
        item.mPlaylistIndex = 0;
        item.mBandwidth = 0;
        mBandwidthItems.push(item);
    }


    mMaxWidth = maxWidth > 0 ? maxWidth : mMaxWidth;
    mMaxHeight = maxHeight > 0 ? maxHeight : mMaxHeight;


    mPlaylist->pickRandomMediaItems();
    changeConfiguration(
            0LL /* timeUs */, initialBandwidthIndex, false /* pickTrack */);
}

上面的代码主要是根据URL返回M3U文件,获取对应的BandwidthIndex,如果熟悉M3U文件,可以知道M3U有一级索引和二级索引。

如果想要获得某个Track的信息,得到视频、音频、字幕相关信息,可以通过LiveSession的getTrackInfo方法:

//frameworks/av/media/libstagefright/httplive/LiveSession.cpp
sp<AMessage> LiveSession::getTrackInfo(size_t trackIndex) const {
    if (mPlaylist == NULL) {
        return NULL;
    } else {
        if (trackIndex == mPlaylist->getTrackCount() && mHasMetadata) {
            sp<AMessage> format = new AMessage();
            format->setInt32("type", MEDIA_TRACK_TYPE_METADATA);
            format->setString("language", "und");
            format->setString("mime", MEDIA_MIMETYPE_DATA_TIMED_ID3);
            return format;
        }
        return mPlaylist->getTrackInfo(trackIndex);
    }
}
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值