diff options
-rw-r--r-- | media/libmediaplayerservice/nuplayer/GenericSource.cpp | 11 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/GenericSource.h | 2 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 10 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 11 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerSource.h | 3 | ||||
-rw-r--r-- | media/libstagefright/NuCachedSource2.cpp | 34 | ||||
-rw-r--r-- | media/libstagefright/httplive/LiveSession.cpp | 11 | ||||
-rw-r--r-- | media/libstagefright/httplive/PlaylistFetcher.cpp | 53 | ||||
-rw-r--r-- | media/libstagefright/httplive/PlaylistFetcher.h | 4 | ||||
-rw-r--r-- | media/libstagefright/include/NuCachedSource2.h | 3 |
10 files changed, 126 insertions, 16 deletions
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 511871d..bd67cbd 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -464,6 +464,15 @@ void NuPlayer::GenericSource::resume() { mStarted = true; } +void NuPlayer::GenericSource::disconnect() { + if (mDataSource != NULL) { + // disconnect data source + if (mDataSource->flags() & DataSource::kIsCachingDataSource) { + static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect(); + } + } +} + void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) { if (mDecryptHandle != NULL) { mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position); @@ -942,7 +951,7 @@ status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); sp<AMessage> msg = new AMessage(kWhatSelectTrack, id()); msg->setInt32("trackIndex", trackIndex); - msg->setInt32("select", trackIndex); + msg->setInt32("select", select); sp<AMessage> response; status_t err = msg->postAndAwaitResponse(&response); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index c70c48e..454edeb 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -55,6 +55,8 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual void pause(); virtual void resume(); + virtual void disconnect(); + virtual status_t feedMoreTSData(); virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 9020a8d..7c6d576 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -310,6 +310,16 @@ void NuPlayer::resume() { } void NuPlayer::resetAsync() { + if (mSource != NULL) { + // During a reset, the data source might be unresponsive already, we need to + // disconnect explicitly so that reads exit promptly. + // We can't queue the disconnect request to the looper, as it might be + // queued behind a stuck read and never gets processed. + // Doing a disconnect outside the looper to allows the pending reads to exit + // (either successfully or with error). + mSource->disconnect(); + } + (new AMessage(kWhatReset, id()))->post(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 7dd54c1..4e6b4d8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -263,8 +263,15 @@ status_t NuPlayerDriver::start() { case STATE_PAUSED: case STATE_STOPPED_AND_PREPARED: { - mPlayer->resume(); - mPositionUs -= ALooper::GetNowUs() - mPauseStartedTimeUs; + if (mAtEOS) { + mPlayer->seekToAsync(0); + mAtEOS = false; + mPlayer->resume(); + mPositionUs = -1; + } else { + mPlayer->resume(); + mPositionUs -= ALooper::GetNowUs() - mPauseStartedTimeUs; + } break; } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 7ccf3b1..7d994fa 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -67,6 +67,9 @@ struct NuPlayer::Source : public AHandler { virtual void pause() {} virtual void resume() {} + // Explicitly disconnect the underling data source + virtual void disconnect() {} + // Returns OK iff more data was available, // an error or ERROR_END_OF_STREAM if not. virtual status_t feedMoreTSData() = 0; diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index c1feff8..be2a873 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -191,6 +191,7 @@ NuCachedSource2::NuCachedSource2( mFinalStatus(OK), mLastAccessPos(0), mFetching(true), + mDisconnecting(false), mLastFetchTimeUs(-1), mNumRetriesLeft(kMaxNumRetries), mHighwaterThresholdBytes(kDefaultHighWaterThreshold), @@ -244,6 +245,23 @@ status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) { return ERROR_UNSUPPORTED; } +void NuCachedSource2::disconnect() { + if (mSource->flags() & kIsHTTPBasedSource) { + ALOGV("disconnecting HTTPBasedSource"); + + { + Mutex::Autolock autoLock(mLock); + // set mDisconnecting to true, if a fetch returns after + // this, the source will be marked as EOS. + mDisconnecting = true; + } + + // explicitly disconnect from the source, to allow any + // pending reads to return more promptly + static_cast<HTTPBase *>(mSource.get())->disconnect(); + } +} + status_t NuCachedSource2::setCacheStatCollectFreq(int32_t freqMs) { if (mSource->flags() & kIsHTTPBasedSource) { HTTPBase *source = static_cast<HTTPBase *>(mSource.get()); @@ -327,7 +345,14 @@ void NuCachedSource2::fetchInternal() { Mutex::Autolock autoLock(mLock); - if (n < 0) { + if (n == 0 || mDisconnecting) { + ALOGI("ERROR_END_OF_STREAM"); + + mNumRetriesLeft = 0; + mFinalStatus = ERROR_END_OF_STREAM; + + mCache->releasePage(page); + } else if (n < 0) { mFinalStatus = n; if (n == ERROR_UNSUPPORTED || n == -EPIPE) { // These are errors that are not likely to go away even if we @@ -337,13 +362,6 @@ void NuCachedSource2::fetchInternal() { ALOGE("source returned error %zd, %d retries left", n, mNumRetriesLeft); mCache->releasePage(page); - } else if (n == 0) { - ALOGI("ERROR_END_OF_STREAM"); - - mNumRetriesLeft = 0; - mFinalStatus = ERROR_END_OF_STREAM; - - mCache->releasePage(page); } else { if (mFinalStatus != OK) { ALOGI("retrying a previously failed read succeeded."); diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 3720085..7786c27 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -158,9 +158,16 @@ status_t LiveSession::dequeueAccessUnit( // wait for counterpart sp<AnotherPacketSource> otherSource; - if (stream == STREAMTYPE_AUDIO && (mStreamMask & STREAMTYPE_VIDEO)) { + uint32_t mask = mNewStreamMask & mStreamMask; + uint32_t fetchersMask = 0; + for (size_t i = 0; i < mFetcherInfos.size(); ++i) { + uint32_t fetcherMask = mFetcherInfos.valueAt(i).mFetcher->getStreamTypeMask(); + fetchersMask |= fetcherMask; + } + mask &= fetchersMask; + if (stream == STREAMTYPE_AUDIO && (mask & STREAMTYPE_VIDEO)) { otherSource = mPacketSources.valueFor(STREAMTYPE_VIDEO); - } else if (stream == STREAMTYPE_VIDEO && (mStreamMask & STREAMTYPE_AUDIO)) { + } else if (stream == STREAMTYPE_VIDEO && (mask & STREAMTYPE_AUDIO)) { otherSource = mPacketSources.valueFor(STREAMTYPE_AUDIO); } if (otherSource != NULL && !otherSource->hasBufferAvailable(&finalResult)) { diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 1166762..f78f8b4 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -1009,7 +1009,16 @@ void PlaylistFetcher::onDownloadNext() { // bulk extract non-ts files if (tsBuffer == NULL) { - err = extractAndQueueAccessUnits(buffer, itemMeta); + err = extractAndQueueAccessUnits(buffer, itemMeta); + if (err == -EAGAIN) { + // starting sequence number too low/high + postMonitorQueue(); + return; + } else if (err == ERROR_OUT_OF_RANGE) { + // reached stopping point + stopAsync(/* clear = */false); + return; + } } if (err != OK) { @@ -1552,14 +1561,52 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits( if (startTimeUs < mStartTimeUs) { continue; } + + if (mStartTimeUsNotify != NULL) { + int32_t targetDurationSecs; + CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs)); + int64_t targetDurationUs = targetDurationSecs * 1000000ll; + + // Duplicated logic from how we handle .ts playlists. + if (mStartup && mSegmentStartTimeUs >= 0 + && timeUs - mStartTimeUs > targetDurationUs) { + int32_t newSeqNumber = getSeqNumberWithAnchorTime(timeUs); + if (newSeqNumber >= mSeqNumber) { + --mSeqNumber; + } else { + mSeqNumber = newSeqNumber; + } + return -EAGAIN; + } + + mStartTimeUsNotify->setInt64("timeUsAudio", timeUs); + mStartTimeUsNotify->setInt32("discontinuitySeq", mDiscontinuitySeq); + mStartTimeUsNotify->setInt32("streamMask", LiveSession::STREAMTYPE_AUDIO); + mStartTimeUsNotify->post(); + mStartTimeUsNotify.clear(); + } + } + + if (mStopParams != NULL) { + // Queue discontinuity in original stream. + int32_t discontinuitySeq; + int64_t stopTimeUs; + if (!mStopParams->findInt32("discontinuitySeq", &discontinuitySeq) + || discontinuitySeq > mDiscontinuitySeq + || !mStopParams->findInt64("timeUsAudio", &stopTimeUs) + || (discontinuitySeq == mDiscontinuitySeq && unitTimeUs >= stopTimeUs)) { + packetSource->queueAccessUnit(mSession->createFormatChangeBuffer()); + mStreamTypeMask = 0; + mPacketSources.clear(); + return ERROR_OUT_OF_RANGE; + } } sp<ABuffer> unit = new ABuffer(aac_frame_length); memcpy(unit->data(), adtsHeader, aac_frame_length); unit->meta()->setInt64("timeUs", unitTimeUs); - unit->meta()->setInt64("segmentStartTimeUs", getSegmentStartTimeUs(mSeqNumber)); - unit->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq); + setAccessUnitProperties(unit, packetSource); packetSource->queueAccessUnit(unit); } diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 4ba37fa..4b09df1 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -69,6 +69,10 @@ struct PlaylistFetcher : public AHandler { void resumeUntilAsync(const sp<AMessage> ¶ms); + uint32_t getStreamTypeMask() const { + return mStreamTypeMask; + } + protected: virtual ~PlaylistFetcher(); virtual void onMessageReceived(const sp<AMessage> &msg); diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index 5db4b4b..4252706 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -37,6 +37,8 @@ struct NuCachedSource2 : public DataSource { virtual ssize_t readAt(off64_t offset, void *data, size_t size); + virtual void disconnect(); + virtual status_t getSize(off64_t *size); virtual uint32_t flags(); @@ -103,6 +105,7 @@ private: off64_t mLastAccessPos; sp<AMessage> mAsyncResult; bool mFetching; + bool mDisconnecting; int64_t mLastFetchTimeUs; int32_t mNumRetriesLeft; |