分析過(guò)程:將Awesomeplayer中的log開(kāi)關(guān)打開(kāi),發(fā)現(xiàn)剛準(zhǔn)備好播放的時(shí)候,下面的log就打出來(lái)了ALOGV("MEDIA_PLAYBACK_COMPLETE");那下面就以這個(gè)為線(xiàn)索進(jìn)行跟蹤問(wèn)題原因了voidAwesomePlayer::onStreamDone() { // Posted whenever anystream finishes playing. if ((mFlags& LOOPING) { ...... } else { ALOGV("MEDIA_PLAYBACK_COMPLETE"); notifyListener_l(MEDIA_PLAYBACK_COMPLETE); pause_l(true ); modifyFlags(AT_EOS, SET); }}voidAwesomePlayer::postStreamDoneEvent_l(status_t status){ mStreamDoneStatus =status; mQueue.postEvent(mStreamDoneEvent);}postStreamDoneEvent_l有兩個(gè)地方發(fā)出:第一次在onVideEvent里面,因?yàn)槭且纛l,應(yīng)當(dāng)都不會(huì)進(jìn)入這里面第二次是在下面這個(gè)函數(shù)中,這個(gè)函數(shù)作為一個(gè)事件,用來(lái)不斷檢查音頻文件是否播放完成void AwesomePlayer::onCheckAudioStatus() {{ Mutex::AutolockautoLock(mAudioLock); status_tfinalStatus; //mWatchForAudioEOS這個(gè)變量肯定為true //mAudioPlayer->reachedEOS(&finalStatus)這個(gè)條件滿(mǎn)足了導(dǎo)致 if (mWatchForAudioEOS&& mAudioPlayer->reachedEOS(&finalStatus)){ mWatchForAudioEOS = false; modifyFlags(AUDIO_AT_EOS, SET); modifyFlags(FIRST_FRAME, SET); postStreamDoneEvent_l(finalStatus); }}下面跟蹤mAudioPlayer->reachedEOSbool AudioPlayer::reachedEOS(status_t *finalStatus) { *finalStatus = OK; Mutex::AutolockautoLock(mLock); *finalStatus =mFinalStatus; returnmReachedEOS;}從結(jié)果來(lái)看,這里返回的mReachedEOS肯定為true,而且finalStatus為ERROR_END_OF_STREAM在AudioPlayer中搜索設(shè)置mReachedEOS為true的地方,找到如下的地方:size_t AudioPlayer::fillBuffer(void *data, size_t size){ if (mNumFramesPlayed ==0) { ALOGV("AudioCallback"); }
if (mReachedEOS) { return 0; }

bool postSeekComplete =false; bool postEOS =false; int64_t postEOSDelayUs =0;
size_t size_done =0; size_t size_remaining =size; while (size_remaining> 0) { if (mInputBuffer == NULL) { status_terr; //下面的ifelse需要確定是走哪個(gè)分支 if(mIsFirstBuffer) { mInputBuffer =mFirstBuffer; mFirstBuffer = NULL; err =mFirstBufferResult; mIsFirstBuffer = false; } else{ err =mSource->read(&mInputBuffer,&options); } CHECK((err== OK && mInputBuffer !=NULL) || (err != OK &&mInputBuffer == NULL)); Mutex::Autolock autoLock(mLock); mReachedEOS = true; mFinalStatus = err; break; }也就是在調(diào)用mSource->read(&mInputBuffer,&options)時(shí)出錯(cuò)下面是視頻播放中一系列read的調(diào)用關(guān)系:audioplayer回調(diào)函數(shù)---fillBuffer---AudioPlayer::read()----OMXCodec::read()----各個(gè)分離器Source::read()(這里是AACSource::read())省略中間的過(guò)程,直接定位到AACExtractor.cpp這個(gè)文件中的read()函數(shù):發(fā)現(xiàn)有這么一段代碼:size_t frameSize, frameSizeWithoutHeader, headerSize;if ((seekFrame >= mOffsetVector.size()) ||(frameSize = getAdtsFrameLength(mDataSource, mOffset,&headerSize)) == 0) { return ERROR_END_OF_STREAM;}打log發(fā)現(xiàn),程序進(jìn)入了這個(gè)if分支,也就是出現(xiàn)問(wèn)題的原因了,下面就要分析為什么會(huì)進(jìn)入這個(gè)if分支,由于||是斷路操作符,第一個(gè)條件滿(mǎn)足了就沒(méi)有執(zhí)行后面的也就是seekFrame >=mOffsetVector.size()條件滿(mǎn)足了,這里兩者都為0mOffsetVector賦值的地方也就是在AACExtractor的構(gòu)造函數(shù)中,構(gòu)造函數(shù)中有非常關(guān)鍵的下面的代碼: if(mDataSource->getSize(&streamSize)== OK) { while (offset <streamSize) { if((frameSize = getAdtsFrameLength(source, offset, NULL)) == 0){ return; } mOffsetVector.push(offset); offset +=frameSize; numFrames++; } // Round up and get the duration mFrameDurationUs = (1024 * 1000000ll + (sr - 1))/ sr; duration = numFrames * mFrameDurationUs; mMeta->setInt64(kKeyDuration,duration); }這個(gè)if分支里面有個(gè)while循環(huán)用來(lái)計(jì)算幀數(shù),并且最后計(jì)算這個(gè)文件的時(shí)長(zhǎng),打log發(fā)現(xiàn),出問(wèn)題的服務(wù)器上并沒(méi)有進(jìn)入這個(gè)if條件,而正常的服務(wù)器進(jìn)入了。分析if中的條件:mDataSource->getSize(&streamSize) ==OK跟蹤一下這個(gè)代碼:mDataSource是NuCacheSource2.cppstatus_t NuCachedSource2::getSize(off64_t *size) { returnmSource->getSize(size); //mSource是ChromiumHTTPDataSource.cpp}status_t ChromiumHTTPDataSource::getSize(off64_t *size){ Mutex::AutolockautoLock(mLock); if(mContentSize < 0) { return ERROR_UNSUPPORTED; } *size =mContentSize; return OK;}由于這個(gè)方法沒(méi)有返回ok,也就是mContentSize 小于0了賦值的地方就一處:void ChromiumHTTPDataSource::onConnectionEstablished( int64_t contentSize, const char *contentType){ mState =CONNECTED; mContentSize = (contentSize < 0) ? -1 :contentSize + mCurrentOffset; mContentType =String8(contentType); mCondition.broadcast();}這個(gè)函數(shù)是在服務(wù)器連接上的回調(diào)中調(diào)用的,在support.cpp中調(diào)用,具體看一下代碼void SfDelegate::OnResponseStarted(net::URLRequest *request){ MY_LOGV("OnResponseStarted");
std::stringheaders; request->GetAllResponseHeaders(&headers);
MY_LOGV(StringPrintf("response headers: %s",headers.c_str()).c_str());
std::stringcontentType; request->GetResponseHeaderByName("Content-Type",&contentType);
mOwner->onConnectionEstablished( request->GetExpectedContentSize(),contentType.c_str());}request->GetExpectedContentSize()用來(lái)從服務(wù)器發(fā)送的報(bào)文中獲取文件的大小,也就是這里沒(méi)有獲取到,導(dǎo)致后面沒(méi)有設(shè)置成功。分析到這里,就自然而然的想到去抓包分析服務(wù)器返回的報(bào)文,抓取ip log發(fā)現(xiàn):正常情況的如下,發(fā)送的報(bào)文中有如下信息:content-length: 2102023而不正常的情況,采用的是另一套標(biāo)準(zhǔn),發(fā)送如下信息:transfer-encoding:chunked這種方式?jīng)]有具體返回文件的長(zhǎng)度,綜上也就是最終導(dǎo)致問(wèn)題出現(xiàn)的原因。
其實(shí)谷歌原始代碼中是沒(méi)有seekFrame >=mOffsetVector.size()這個(gè)判斷條件的。
愛(ài)華網(wǎng)本文地址 » http://www.klfzs.com/a/25101017/353063.html
愛(ài)華網(wǎng)



