在mps的setDataSource中,根据url判断应该生成那种dataSource,然后获取默认的player,即nuplayer。进入NuPlayerDriver的setDataSource,
再进入void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) {
#ifdef MTK_AOSP_ENHANCEMENT
mIsStreamSource = true;
#endif
sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
msg->setObject("source", new StreamingSource(notify, source));
msg->post();
}
到了NuPlayer异步消息的世界,进入setDataSourceAsync
首先判断是什么流媒体
if (!strncasecmp(url, "http://", 7)
|| !strncasecmp(url, "https://", 8)) {
mDataSourceType = SOURCE_Http;
ALOGI("Is http Streaming");
生成一个sp<GenericSource> genericSource =
new GenericSource(notify, mUIDValid, mUID);
然后触发了kWhatSetDataSource
进入NuPlayerDriver的
void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
Mutex::Autolock autoLock(mLock);
CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
mAsyncResult = err;
mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
#ifdef MTK_AOSP_ENHANCEMENT
ALOGD("after notifySetDataSourceCompleted mState=%d", mState);
#endif
mCondition.broadcast();
}
注意,mCondition是在MPS调用NuPlayerDriver的API的时候就已经wait了的
status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
ALOGV("setDataSource(%p) file(%d)", this, fd);
Mutex::Autolock autoLock(mLock);
if (mState != STATE_IDLE) {
return INVALID_OPERATION;
}
mState = STATE_SET_DATASOURCE_PENDING;
mPlayer->setDataSourceAsync(fd, offset, length);
while (mState == STATE_SET_DATASOURCE_PENDING) {
mCondition.wait(mLock);
}
return mAsyncResult;
}
好,下面该prepare了
status_t NuPlayerDriver::prepare_l() {
switch (mState) {
case STATE_UNPREPARED:
mState = STATE_PREPARING;
// Make sure we're not posting any notifications, success or
// failure information is only communicated through our result
// code.
mIsAsyncPrepare = false;
mPlayer->prepareAsync();
while (mState == STATE_PREPARING) {
mCondition.wait(mLock);
}
return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
case STATE_STOPPED:
// this is really just paused. handle as seek to start
mAtEOS = false;
mState = STATE_STOPPED_AND_PREPARING;
mIsAsyncPrepare = false;
mPlayer->seekToAsync(0, true /* needNotify */);
while (mState == STATE_STOPPED_AND_PREPARING) {
mCondition.wait(mLock);
}
return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
default:
return INVALID_OPERATION;
};
}
进到NuPlayer的消息处理机制
case kWhatPrepare:
{
#ifdef MTK_AOSP_ENHANCEMENT
ATRACE_ASYNC_BEGIN("Prepare",mPlayerCnt);
ALOGD("kWhatPrepare, source type = %d", (int)mDataSourceType);
if (mPrepare == PREPARING)
break;
mPrepare = PREPARING;
if (mSource == NULL) {
ALOGW("prepare error: source is not ready");
finishPrepare(UNKNOWN_ERROR);
break;
}
#endif
mSource->prepareAsync();
break;
}
这个mSource是GenericSource
进入了onPrepareAsync
此时去create 一个dataSource
mDataSource = DataSource::CreateFromURI(
mHTTPService, uri, &mUriHeaders, &mContentType,
static_cast<HTTPBase *>(mHttpSource.get()));
此时就涉及到两个Source,一个是从网络获取数据的Http,一个是cache在本地的流媒体数据
Http的Source被这样创建
mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
mHttpSource继承于DataSource
第一个Source是聚合在NuCachedSource2中的一个Source
cache的Source被这样创建,本质上也是一个DataSource,因为NuCachedSource2是dataSource的子类
source = new NuCachedSource2(
httpSource,
cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
disconnectAtHighwatermark);
然后进入initFromDataSource,也就是去选择extractor的类型,这个需要一些数据来判断是哪种流媒体格式
extractor = MediaExtractor::Create(mDataSource,
mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
那些初始下载的数据是什么时候下的呢?在创建NuCachedSource2的时候就开始了
这是另外一个线程在做的事情
ssize_t n = mSource->readAt(
mCacheOffset + mCache->totalSize(), page->mData, kPageSize);
一次性获取kPageSize大小的数据
此时是靠IMediaHTTPConnection来通过匿名共享内存和binder获取的
Bn的部分在MediaHTTPConnection.java (base\media\java\android\media)
而它使用的又是 HttpURLConnection,是现在libcore下,属于基础架构
回到Extractor,它会调用ssize_t NuCachedSource2::readAt(off64_t offset, void *data, size_t size) {
发kWhatRead调用onRead,然后调用readInternal,从mCache里面copy数据
mCache->copy(delta, data, avail);
有多少拷多少,data是输出参数,给Extractor
注意,判断是什么类型是需要一点数据,这点数据往往就是tmd的tts数据了
bool DataSource::sniff(
String8 *mimeType, float *confidence, sp<AMessage> *meta) {
策略是所有Sniff,挨个闻一遍,哪个confidence高用谁的,Sniff是Extractor的一个副产品