diff options
19 files changed, 299 insertions, 142 deletions
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index c69f74b..d433a4d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -629,15 +629,16 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */); sp<AMessage> videoFormat = mSource->getFormat(false /* audio */); audio_stream_type_t streamType = mAudioSink->getAudioStreamType(); - bool canOffload = canOffloadStream(audioMeta, (videoFormat != NULL), - true /* is_streaming */, streamType); + const bool hasVideo = (videoFormat != NULL); + const bool canOffload = canOffloadStream( + audioMeta, hasVideo, true /* is_streaming */, streamType); if (canOffload) { if (!mOffloadAudio) { mRenderer->signalEnableOffloadAudio(); } // open audio sink early under offload mode. sp<AMessage> format = mSource->getFormat(true /*audio*/); - openAudioSink(format, true /*offloadOnly*/); + tryOpenAudioSinkForOffload(format, hasVideo); } instantiateDecoder(true, &mAudioDecoder); } @@ -774,6 +775,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { // Decoder errors can be due to Source (e.g. from streaming), // or from decoding corrupted bitstreams, or from other decoder // MediaCodec operations (e.g. from an ongoing reset or seek). + // They may also be due to openAudioSink failure at + // decoder start or after a format change. // // We try to gracefully shut down the affected decoder if possible, // rather than trying to force the shutdown with something @@ -1146,28 +1149,16 @@ void NuPlayer::postScanSources() { mScanSourcesPending = true; } -void NuPlayer::openAudioSink(const sp<AMessage> &format, bool offloadOnly) { - uint32_t flags; - int64_t durationUs; - bool hasVideo = (mVideoDecoder != NULL); - // FIXME: we should handle the case where the video decoder - // is created after we receive the format change indication. - // Current code will just make that we select deep buffer - // with video which should not be a problem as it should - // not prevent from keeping A/V sync. - if (!hasVideo && - mSource->getDuration(&durationUs) == OK && - durationUs - > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { - flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; - } else { - flags = AUDIO_OUTPUT_FLAG_NONE; - } - - mOffloadAudio = mRenderer->openAudioSink( - format, offloadOnly, hasVideo, flags); +void NuPlayer::tryOpenAudioSinkForOffload(const sp<AMessage> &format, bool hasVideo) { + // Note: This is called early in NuPlayer to determine whether offloading + // is possible; otherwise the decoders call the renderer openAudioSink directly. - if (mOffloadAudio) { + status_t err = mRenderer->openAudioSink( + format, true /* offloadOnly */, hasVideo, AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio); + if (err != OK) { + // Any failure we turn off mOffloadAudio. + mOffloadAudio = false; + } else if (mOffloadAudio) { sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */); sendMetaDataToHal(mAudioSink, audioMeta); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 6be38a4..1569816 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -188,7 +188,7 @@ private: mFlushComplete[1][1] = false; } - void openAudioSink(const sp<AMessage> &format, bool offloadOnly); + void tryOpenAudioSinkForOffload(const sp<AMessage> &format, bool hasVideo); void closeAudioSink(); status_t instantiateDecoder(bool audio, sp<DecoderBase> *decoder); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 012d33e..6ad28b5 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -44,7 +44,7 @@ NuPlayer::Decoder::Decoder( const sp<Renderer> &renderer, const sp<NativeWindowWrapper> &nativeWindow, const sp<CCDecoder> &ccDecoder) - : mNotify(notify), + : DecoderBase(notify), mNativeWindow(nativeWindow), mSource(source), mRenderer(renderer), @@ -56,7 +56,6 @@ NuPlayer::Decoder::Decoder( mIsVideoAVC(false), mIsSecure(false), mFormatChangePending(false), - mBufferGeneration(0), mPaused(true), mResumePending(false), mComponentName("decoder") { @@ -336,20 +335,6 @@ void NuPlayer::Decoder::doRequestBuffers() { } } -void NuPlayer::Decoder::handleError(int32_t err) -{ - // We cannot immediately release the codec due to buffers still outstanding - // in the renderer. We signal to the player the error so it can shutdown/release the - // decoder after flushing and increment the generation to discard unnecessary messages. - - ++mBufferGeneration; - - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatError); - notify->setInt32("err", err); - notify->post(); -} - bool NuPlayer::Decoder::handleAnInputBuffer() { if (mFormatChangePending) { return false; @@ -462,8 +447,14 @@ bool NuPlayer::Decoder::handleAnOutputBuffer() { flags = AUDIO_OUTPUT_FLAG_NONE; } - mRenderer->openAudioSink( - format, false /* offloadOnly */, hasVideo, flags); + res = mRenderer->openAudioSink( + format, false /* offloadOnly */, hasVideo, flags, NULL /* isOffloaded */); + if (res != OK) { + ALOGE("Failed to open AudioSink on format change for %s (err=%d)", + mComponentName.c_str(), res); + handleError(res); + return false; + } } return true; } else if (res == INFO_DISCONTINUITY) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 2c08f0d..1bfa94f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -53,7 +53,6 @@ private: kWhatRenderBuffer = 'rndr', }; - sp<AMessage> mNotify; sp<NativeWindowWrapper> mNativeWindow; sp<Source> mSource; @@ -83,12 +82,10 @@ private: bool mIsSecure; bool mFormatChangePending; - int32_t mBufferGeneration; bool mPaused; bool mResumePending; AString mComponentName; - void handleError(int32_t err); bool handleAnInputBuffer(); bool handleAnOutputBuffer(); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp index 4164350..d56fc4d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp @@ -28,8 +28,10 @@ namespace android { -NuPlayer::DecoderBase::DecoderBase() - : mRequestInputBuffersPending(false) { +NuPlayer::DecoderBase::DecoderBase(const sp<AMessage> ¬ify) + : mNotify(notify), + mBufferGeneration(0), + mRequestInputBuffersPending(false) { // Every decoder has its own looper because MediaCodec operations // are blocking, but NuPlayer needs asynchronous operations. mDecoderLooper = new ALooper; @@ -180,5 +182,19 @@ void NuPlayer::DecoderBase::onMessageReceived(const sp<AMessage> &msg) { } } +void NuPlayer::DecoderBase::handleError(int32_t err) +{ + // We cannot immediately release the codec due to buffers still outstanding + // in the renderer. We signal to the player the error so it can shutdown/release the + // decoder after flushing and increment the generation to discard unnecessary messages. + + ++mBufferGeneration; + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatError); + notify->setInt32("err", err); + notify->post(); +} + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h index 5feb6a1..6732ff4 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h @@ -29,7 +29,7 @@ struct MediaCodec; struct MediaBuffer; struct NuPlayer::DecoderBase : public AHandler { - DecoderBase(); + DecoderBase(const sp<AMessage> ¬ify); void configure(const sp<AMessage> &format); void init(); @@ -71,6 +71,10 @@ protected: void onRequestInputBuffers(); void scheduleRequestBuffers(); virtual void doRequestBuffers() = 0; + virtual void handleError(int32_t err); + + sp<AMessage> mNotify; + int32_t mBufferGeneration; private: enum { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp index 79b7a3c..9f7f09a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp @@ -43,12 +43,11 @@ NuPlayer::DecoderPassThrough::DecoderPassThrough( const sp<AMessage> ¬ify, const sp<Source> &source, const sp<Renderer> &renderer) - : mNotify(notify), + : DecoderBase(notify), mSource(source), mRenderer(renderer), mSkipRenderingUntilMediaTimeUs(-1ll), mPaused(false), - mBufferGeneration(0), mReachedEOS(true), mPendingAudioErr(OK), mPendingBuffersToDrain(0), @@ -75,17 +74,15 @@ void NuPlayer::DecoderPassThrough::onConfigure(const sp<AMessage> &format) { onRequestInputBuffers(); - uint32_t flags; - int64_t durationUs; - if (mSource->getDuration(&durationUs) == OK && - durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { - flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; - } else { - flags = AUDIO_OUTPUT_FLAG_NONE; + // The audio sink is already opened before the PassThrough decoder is created. + // Opening again might be relevant if decoder is instantiated after shutdown and + // format is different. + status_t err = mRenderer->openAudioSink( + format, true /* offloadOnly */, false /* hasVideo */, + AUDIO_OUTPUT_FLAG_NONE /* flags */, NULL /* isOffloaded */); + if (err != OK) { + handleError(err); } - - mRenderer->openAudioSink( - format, true /* offloadOnly */, false /* hasVideo */, flags); } void NuPlayer::DecoderPassThrough::onSetRenderer( diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h index 37b28c8..a6e1faf 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h @@ -52,13 +52,11 @@ private: kWhatBufferConsumed = 'bufC', }; - sp<AMessage> mNotify; sp<Source> mSource; sp<Renderer> mRenderer; int64_t mSkipRenderingUntilMediaTimeUs; bool mPaused; - int32_t mBufferGeneration; bool mReachedEOS; // Used by feedDecoderInputData to aggregate small buffers into diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index f7d30a8..a1e1aec 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -250,11 +250,12 @@ void NuPlayer::Renderer::setPauseStartedTimeRealUs(int64_t realUs) { mPauseStartedTimeRealUs = realUs; } -bool NuPlayer::Renderer::openAudioSink( +status_t NuPlayer::Renderer::openAudioSink( const sp<AMessage> &format, bool offloadOnly, bool hasVideo, - uint32_t flags) { + uint32_t flags, + bool *isOffloaded) { sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, id()); msg->setMessage("format", format); msg->setInt32("offload-only", offloadOnly); @@ -264,9 +265,15 @@ bool NuPlayer::Renderer::openAudioSink( sp<AMessage> response; msg->postAndAwaitResponse(&response); - int32_t offload; - CHECK(response->findInt32("offload", &offload)); - return (offload != 0); + int32_t err; + if (!response->findInt32("err", &err)) { + err = INVALID_OPERATION; + } else if (err == OK && isOffloaded != NULL) { + int32_t offload; + CHECK(response->findInt32("offload", &offload)); + *isOffloaded = (offload != 0); + } + return err; } void NuPlayer::Renderer::closeAudioSink() { @@ -292,10 +299,11 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) { uint32_t flags; CHECK(msg->findInt32("flags", (int32_t *)&flags)); - bool offload = onOpenAudioSink(format, offloadOnly, hasVideo, flags); + status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags); sp<AMessage> response = new AMessage; - response->setInt32("offload", offload); + response->setInt32("err", err); + response->setInt32("offload", offloadingAudio()); uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); @@ -651,8 +659,9 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { ssize_t written = mAudioSink->write(entry->mBuffer->data() + entry->mOffset, copy); if (written < 0) { - // An error in AudioSink write is fatal here. - LOG_ALWAYS_FATAL("AudioSink write error(%zd) when writing %zu bytes", written, copy); + // An error in AudioSink write. Perhaps the AudioSink was not properly opened. + ALOGE("AudioSink write error(%zd) when writing %zu bytes", written, copy); + break; } entry->mOffset += written; @@ -1321,7 +1330,7 @@ void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() { } } -bool NuPlayer::Renderer::onOpenAudioSink( +status_t NuPlayer::Renderer::onOpenAudioSink( const sp<AMessage> &format, bool offloadOnly, bool hasVideo, @@ -1383,7 +1392,7 @@ bool NuPlayer::Renderer::onOpenAudioSink( if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) { ALOGV("openAudioSink: no change in offload mode"); // no change from previous configuration, everything ok. - return offloadingAudio(); + return OK; } ALOGV("openAudioSink: try to open AudioSink in offload mode"); uint32_t offloadFlags = flags; @@ -1429,7 +1438,7 @@ bool NuPlayer::Renderer::onOpenAudioSink( audioSinkChanged = true; mAudioSink->close(); mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; - CHECK_EQ(mAudioSink->open( + status_t err = mAudioSink->open( sampleRate, numChannels, (audio_channel_mask_t)channelMask, @@ -1437,8 +1446,11 @@ bool NuPlayer::Renderer::onOpenAudioSink( 8 /* bufferCount */, NULL, NULL, - (audio_output_flags_t)pcmFlags), - (status_t)OK); + (audio_output_flags_t)pcmFlags); + if (err != OK) { + ALOGW("openAudioSink: non offloaded open failed status: %d", err); + return err; + } mAudioSink->start(); } if (audioSinkChanged) { @@ -1447,8 +1459,7 @@ bool NuPlayer::Renderer::onOpenAudioSink( if (offloadingAudio()) { mAudioOffloadTornDown = false; } - - return offloadingAudio(); + return OK; } void NuPlayer::Renderer::onCloseAudioSink() { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 14ae924..406c64c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -73,11 +73,12 @@ struct NuPlayer::Renderer : public AHandler { int64_t getVideoLateByUs(); void setPauseStartedTimeRealUs(int64_t realUs); - bool openAudioSink( + status_t openAudioSink( const sp<AMessage> &format, bool offloadOnly, bool hasVideo, - uint32_t flags); + uint32_t flags, + bool *isOffloaded); void closeAudioSink(); enum { @@ -209,7 +210,7 @@ private: void onResume(); void onSetVideoFrameRate(float fps); void onAudioOffloadTearDown(AudioOffloadTearDownReason reason); - bool onOpenAudioSink( + status_t onOpenAudioSink( const sp<AMessage> &format, bool offloadOnly, bool hasVideo, diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 52ae9ee..0282a9f 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -50,7 +50,7 @@ NuPlayer::RTSPSource::RTSPSource( mState(DISCONNECTED), mFinalResult(OK), mDisconnectReplyID(0), - mBuffering(true), + mBuffering(false), mSeekGeneration(0), mEOSTimeoutAudio(0), mEOSTimeoutVideo(0) { @@ -106,9 +106,7 @@ void NuPlayer::RTSPSource::prepareAsync() { mHandler->connect(); } - sp<AMessage> notifyStart = dupNotify(); - notifyStart->setInt32("what", kWhatBufferingStart); - notifyStart->post(); + startBufferingIfNecessary(); } void NuPlayer::RTSPSource::start() { @@ -144,6 +142,7 @@ void NuPlayer::RTSPSource::resume() { } status_t NuPlayer::RTSPSource::feedMoreTSData() { + Mutex::Autolock _l(mBufferingLock); return mFinalResult; } @@ -195,16 +194,8 @@ bool NuPlayer::RTSPSource::haveSufficientDataOnAllTracks() { status_t NuPlayer::RTSPSource::dequeueAccessUnit( bool audio, sp<ABuffer> *accessUnit) { - if (mBuffering) { - if (!haveSufficientDataOnAllTracks()) { - return -EWOULDBLOCK; - } - - mBuffering = false; - - sp<AMessage> notify = dupNotify(); - notify->setInt32("what", kWhatBufferingEnd); - notify->post(); + if (!stopBufferingIfNecessary()) { + return -EWOULDBLOCK; } sp<AnotherPacketSource> source = getSource(audio); @@ -246,11 +237,7 @@ status_t NuPlayer::RTSPSource::dequeueAccessUnit( if (!(otherSource != NULL && otherSource->isFinished(mediaDurationUs))) { // We should not enter buffering mode // if any of the sources already have detected EOS. - mBuffering = true; - - sp<AMessage> notify = dupNotify(); - notify->setInt32("what", kWhatBufferingStart); - notify->post(); + startBufferingIfNecessary(); } return -EWOULDBLOCK; @@ -630,7 +617,7 @@ void NuPlayer::RTSPSource::onSDPLoaded(const sp<AMessage> &msg) { } mState = DISCONNECTED; - mFinalResult = err; + setError(err); if (mDisconnectReplyID != 0) { finishDisconnectIfPossible(); @@ -657,7 +644,7 @@ void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) { } mState = DISCONNECTED; - mFinalResult = err; + setError(err); if (mDisconnectReplyID != 0) { finishDisconnectIfPossible(); @@ -678,4 +665,40 @@ void NuPlayer::RTSPSource::finishDisconnectIfPossible() { mDisconnectReplyID = 0; } +void NuPlayer::RTSPSource::setError(status_t err) { + Mutex::Autolock _l(mBufferingLock); + mFinalResult = err; +} + +void NuPlayer::RTSPSource::startBufferingIfNecessary() { + Mutex::Autolock _l(mBufferingLock); + + if (!mBuffering) { + mBuffering = true; + + sp<AMessage> notify = dupNotify(); + notify->setInt32("what", kWhatBufferingStart); + notify->post(); + } +} + +bool NuPlayer::RTSPSource::stopBufferingIfNecessary() { + Mutex::Autolock _l(mBufferingLock); + + if (mBuffering) { + if (!haveSufficientDataOnAllTracks()) { + return false; + } + + mBuffering = false; + + sp<AMessage> notify = dupNotify(); + notify->setInt32("what", kWhatBufferingEnd); + notify->post(); + } + + return true; +} + + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h index f1cae53..ac3299a 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.h +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h @@ -97,6 +97,7 @@ private: State mState; status_t mFinalResult; uint32_t mDisconnectReplyID; + Mutex mBufferingLock; bool mBuffering; sp<ALooper> mLooper; @@ -126,6 +127,9 @@ private: bool haveSufficientDataOnAllTracks(); void setEOSTimeout(bool audio, int64_t timeout); + void setError(status_t err); + void startBufferingIfNecessary(); + bool stopBufferingIfNecessary(); DISALLOW_EVIL_CONSTRUCTORS(RTSPSource); }; diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp index 27f5159..b3f224d 100644 --- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp +++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp @@ -37,13 +37,26 @@ NuPlayer::StreamingSource::StreamingSource( const sp<IStreamSource> &source) : Source(notify), mSource(source), - mFinalResult(OK) { + mFinalResult(OK), + mBuffering(false) { } NuPlayer::StreamingSource::~StreamingSource() { + if (mLooper != NULL) { + mLooper->unregisterHandler(id()); + mLooper->stop(); + } } void NuPlayer::StreamingSource::prepareAsync() { + if (mLooper == NULL) { + mLooper = new ALooper; + mLooper->setName("streaming"); + mLooper->start(); + + mLooper->registerHandler(this); + } + notifyVideoSizeChanged(); notifyFlagsChanged(0); notifyPrepared(); @@ -62,13 +75,15 @@ void NuPlayer::StreamingSource::start() { mTSParser = new ATSParser(parserFlags); mStreamListener->start(); + + postReadBuffer(); } status_t NuPlayer::StreamingSource::feedMoreTSData() { - if (mFinalResult != OK) { - return mFinalResult; - } + return postReadBuffer(); +} +void NuPlayer::StreamingSource::onReadBuffer() { for (int32_t i = 0; i < 50; ++i) { char buffer[188]; sp<AMessage> extra; @@ -77,7 +92,7 @@ status_t NuPlayer::StreamingSource::feedMoreTSData() { if (n == 0) { ALOGI("input data EOS reached."); mTSParser->signalEOS(ERROR_END_OF_STREAM); - mFinalResult = ERROR_END_OF_STREAM; + setError(ERROR_END_OF_STREAM); break; } else if (n == INFO_DISCONTINUITY) { int32_t type = ATSParser::DISCONTINUITY_TIME; @@ -88,7 +103,8 @@ status_t NuPlayer::StreamingSource::feedMoreTSData() { IStreamListener::kKeyDiscontinuityMask, &mask)) { if (mask == 0) { ALOGE("Client specified an illegal discontinuity type."); - return ERROR_UNSUPPORTED; + setError(ERROR_UNSUPPORTED); + break; } type = mask; @@ -97,7 +113,6 @@ status_t NuPlayer::StreamingSource::feedMoreTSData() { mTSParser->signalDiscontinuity( (ATSParser::DiscontinuityType)type, extra); } else if (n < 0) { - CHECK_EQ(n, -EWOULDBLOCK); break; } else { if (buffer[0] == 0x00) { @@ -128,22 +143,80 @@ status_t NuPlayer::StreamingSource::feedMoreTSData() { ALOGE("TS Parser returned error %d", err); mTSParser->signalEOS(err); - mFinalResult = err; + setError(err); break; } } } } +} + +status_t NuPlayer::StreamingSource::postReadBuffer() { + { + Mutex::Autolock _l(mBufferingLock); + if (mFinalResult != OK) { + return mFinalResult; + } + if (mBuffering) { + return OK; + } + mBuffering = true; + } + (new AMessage(kWhatReadBuffer, id()))->post(); return OK; } -sp<MetaData> NuPlayer::StreamingSource::getFormatMeta(bool audio) { - ATSParser::SourceType type = - audio ? ATSParser::AUDIO : ATSParser::VIDEO; +bool NuPlayer::StreamingSource::haveSufficientDataOnAllTracks() { + // We're going to buffer at least 2 secs worth data on all tracks before + // starting playback (both at startup and after a seek). - sp<AnotherPacketSource> source = - static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get()); + static const int64_t kMinDurationUs = 2000000ll; + + sp<AnotherPacketSource> audioTrack = getSource(true /*audio*/); + sp<AnotherPacketSource> videoTrack = getSource(false /*audio*/); + + status_t err; + int64_t durationUs; + if (audioTrack != NULL + && (durationUs = audioTrack->getBufferedDurationUs(&err)) + < kMinDurationUs + && err == OK) { + ALOGV("audio track doesn't have enough data yet. (%.2f secs buffered)", + durationUs / 1E6); + return false; + } + + if (videoTrack != NULL + && (durationUs = videoTrack->getBufferedDurationUs(&err)) + < kMinDurationUs + && err == OK) { + ALOGV("video track doesn't have enough data yet. (%.2f secs buffered)", + durationUs / 1E6); + return false; + } + + return true; +} + +void NuPlayer::StreamingSource::setError(status_t err) { + Mutex::Autolock _l(mBufferingLock); + mFinalResult = err; +} + +sp<AnotherPacketSource> NuPlayer::StreamingSource::getSource(bool audio) { + if (mTSParser == NULL) { + return NULL; + } + + sp<MediaSource> source = mTSParser->getSource( + audio ? ATSParser::AUDIO : ATSParser::VIDEO); + + return static_cast<AnotherPacketSource *>(source.get()); +} + +sp<MetaData> NuPlayer::StreamingSource::getFormatMeta(bool audio) { + sp<AnotherPacketSource> source = getSource(audio); if (source == NULL) { return NULL; @@ -154,16 +227,16 @@ sp<MetaData> NuPlayer::StreamingSource::getFormatMeta(bool audio) { status_t NuPlayer::StreamingSource::dequeueAccessUnit( bool audio, sp<ABuffer> *accessUnit) { - ATSParser::SourceType type = - audio ? ATSParser::AUDIO : ATSParser::VIDEO; - - sp<AnotherPacketSource> source = - static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get()); + sp<AnotherPacketSource> source = getSource(audio); if (source == NULL) { return -EWOULDBLOCK; } + if (!haveSufficientDataOnAllTracks()) { + postReadBuffer(); + } + status_t finalResult; if (!source->hasBufferAvailable(&finalResult)) { return finalResult == OK ? -EWOULDBLOCK : finalResult; @@ -186,5 +259,26 @@ bool NuPlayer::StreamingSource::isRealTime() const { return mSource->flags() & IStreamSource::kFlagIsRealTimeData; } +void NuPlayer::StreamingSource::onMessageReceived( + const sp<AMessage> &msg) { + switch (msg->what()) { + case kWhatReadBuffer: + { + onReadBuffer(); + + { + Mutex::Autolock _l(mBufferingLock); + mBuffering = false; + } + break; + } + default: + { + TRESPASS(); + } + } +} + + } // namespace android diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/StreamingSource.h index 412b6c4..1f95f3c 100644 --- a/media/libmediaplayerservice/nuplayer/StreamingSource.h +++ b/media/libmediaplayerservice/nuplayer/StreamingSource.h @@ -25,6 +25,7 @@ namespace android { struct ABuffer; struct ATSParser; +struct AnotherPacketSource; struct NuPlayer::StreamingSource : public NuPlayer::Source { StreamingSource( @@ -43,14 +44,29 @@ struct NuPlayer::StreamingSource : public NuPlayer::Source { protected: virtual ~StreamingSource(); + virtual void onMessageReceived(const sp<AMessage> &msg); + virtual sp<MetaData> getFormatMeta(bool audio); private: + enum { + kWhatReadBuffer, + }; sp<IStreamSource> mSource; status_t mFinalResult; sp<NuPlayerStreamListener> mStreamListener; sp<ATSParser> mTSParser; + bool mBuffering; + Mutex mBufferingLock; + sp<ALooper> mLooper; + + void setError(status_t err); + sp<AnotherPacketSource> getSource(bool audio); + bool haveSufficientDataOnAllTracks(); + status_t postReadBuffer(); + void onReadBuffer(); + DISALLOW_EVIL_CONSTRUCTORS(StreamingSource); }; diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp index 38a1f6b..cbdb816 100644 --- a/media/libstagefright/avc_utils.cpp +++ b/media/libstagefright/avc_utils.cpp @@ -222,28 +222,25 @@ status_t getNextNALUnit( *nalStart = NULL; *nalSize = 0; - if (size == 0) { + if (size < 3) { return -EAGAIN; } - // Skip any number of leading 0x00. - size_t offset = 0; - while (offset < size && data[offset] == 0x00) { - ++offset; - } - - if (offset == size) { - return -EAGAIN; - } // A valid startcode consists of at least two 0x00 bytes followed by 0x01. - - if (offset < 2 || data[offset] != 0x01) { - return ERROR_MALFORMED; + for (; offset + 2 < size; ++offset) { + if (data[offset + 2] == 0x01 && data[offset] == 0x00 + && data[offset + 1] == 0x00) { + break; + } } - - ++offset; + if (offset + 2 >= size) { + *_data = &data[offset]; + *_size = 2; + return -EAGAIN; + } + offset += 3; size_t startOffset = offset; diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml index f599004..85f6615 100644 --- a/media/libstagefright/data/media_codecs_google_audio.xml +++ b/media/libstagefright/data/media_codecs_google_audio.xml @@ -48,7 +48,7 @@ </MediaCodec> <MediaCodec name="OMX.google.vorbis.decoder" type="audio/vorbis"> <Limit name="channel-count" max="8" /> - <Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000,96000" /> + <Limit name="sample-rate" ranges="8000-96000" /> <Limit name="bitrate" range="32000-500000" /> </MediaCodec> <MediaCodec name="OMX.google.opus.decoder" type="audio/opus"> diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index ef1cd3d..042f4e6 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -173,8 +173,9 @@ static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) { return parseAC3SyncFrame(ptr, size, NULL) > 0; } -static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) { - if (size < 3) { +static bool IsSeeminglyValidADTSHeader( + const uint8_t *ptr, size_t size, size_t *frameLength) { + if (size < 7) { // Not enough data to verify header. return false; } @@ -197,6 +198,13 @@ static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) { return false; } + size_t frameLengthInHeader = + ((ptr[3] & 3) << 11) + (ptr[4] << 3) + ((ptr[5] >> 5) & 7); + if (frameLengthInHeader > size) { + return false; + } + + *frameLength = frameLengthInHeader; return true; } @@ -318,8 +326,10 @@ status_t ElementaryStreamQueue::appendData( } #else ssize_t startOffset = -1; + size_t frameLength; for (size_t i = 0; i < size; ++i) { - if (IsSeeminglyValidADTSHeader(&ptr[i], size - i)) { + if (IsSeeminglyValidADTSHeader( + &ptr[i], size - i, &frameLength)) { startOffset = i; break; } @@ -335,6 +345,12 @@ status_t ElementaryStreamQueue::appendData( startOffset); } + if (frameLength != size - startOffset) { + ALOGW("First ADTS AAC frame length is %zd bytes, " + "while the buffer size is %zd bytes.", + frameLength, size - startOffset); + } + data = &ptr[startOffset]; size -= startOffset; #endif diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 08d9eb1..dab6d91 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2688,7 +2688,8 @@ status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp) if (mNormalSink != 0) { return mNormalSink->getTimestamp(timestamp); } - if ((mType == OFFLOAD || mType == DIRECT) && mOutput->stream->get_presentation_position) { + if ((mType == OFFLOAD || mType == DIRECT) + && mOutput != NULL && mOutput->stream->get_presentation_position) { uint64_t position64; int ret = mOutput->stream->get_presentation_position( mOutput->stream, &position64, ×tamp.mTime); diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index e2b6480..17348e9 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -722,7 +722,7 @@ protected: // if muting, wait for the audio in pcm buffer to be drained before proceeding // if unmuting, unmute only after the specified delay // Returns the number of ms waited - uint32_t checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc, + virtual uint32_t checkDeviceMuteStrategies(sp<AudioOutputDescriptor> outputDesc, audio_devices_t prevDevice, uint32_t delayMs); |