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);
}
}