diff options
Diffstat (limited to 'media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp')
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 163 |
1 files changed, 112 insertions, 51 deletions
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 638d9bc..21b74ee 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -20,8 +20,6 @@ #include "NuPlayerRenderer.h" -#include <cutils/properties.h> - #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -38,21 +36,11 @@ namespace android { // Maximum time in paused state when offloading audio decompression. When elapsed, the AudioSink // is closed to allow the audio DSP to power down. -static const int64_t kOffloadPauseMaxUs = 60000000ll; +static const int64_t kOffloadPauseMaxUs = 10000000ll; // static const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll; -static bool sFrameAccurateAVsync = false; - -static void readProperties() { - char value[PROPERTY_VALUE_MAX]; - if (property_get("persist.sys.media.avsync", value, NULL)) { - sFrameAccurateAVsync = - !strcmp("1", value) || !strcasecmp("true", value); - } -} - NuPlayer::Renderer::Renderer( const sp<MediaPlayerBase::AudioSink> &sink, const sp<AMessage> ¬ify, @@ -68,12 +56,16 @@ NuPlayer::Renderer::Renderer( mAudioFirstAnchorTimeMediaUs(-1), mAnchorTimeMediaUs(-1), mAnchorTimeRealUs(-1), + mAnchorNumFramesWritten(-1), + mAnchorMaxMediaUs(-1), mVideoLateByUs(0ll), mHasAudio(false), mHasVideo(false), mPauseStartedTimeRealUs(-1), mFlushingAudio(false), mFlushingVideo(false), + mNotifyCompleteAudio(false), + mNotifyCompleteVideo(false), mSyncQueues(false), mPaused(false), mVideoSampleReceived(false), @@ -85,7 +77,6 @@ NuPlayer::Renderer::Renderer( mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), mTotalBuffersQueued(0), mLastAudioBufferDrained(0) { - readProperties(); } NuPlayer::Renderer::~Renderer() { @@ -116,15 +107,17 @@ void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) { msg->post(); } -void NuPlayer::Renderer::flush(bool audio) { +void NuPlayer::Renderer::flush(bool audio, bool notifyComplete) { { Mutex::Autolock autoLock(mFlushLock); if (audio) { + mNotifyCompleteAudio |= notifyComplete; if (mFlushingAudio) { return; } mFlushingAudio = true; } else { + mNotifyCompleteVideo |= notifyComplete; if (mFlushingVideo) { return; } @@ -155,6 +148,10 @@ void NuPlayer::Renderer::signalDisableOffloadAudio() { (new AMessage(kWhatDisableOffloadAudio, id()))->post(); } +void NuPlayer::Renderer::signalEnableOffloadAudio() { + (new AMessage(kWhatEnableOffloadAudio, id()))->post(); +} + void NuPlayer::Renderer::pause() { (new AMessage(kWhatPause, id()))->post(); } @@ -173,7 +170,8 @@ status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) { return getCurrentPosition(mediaUs, ALooper::GetNowUs()); } -status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs, int64_t nowUs) { +status_t NuPlayer::Renderer::getCurrentPosition( + int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo) { Mutex::Autolock autoLock(mTimeLock); if (!mHasAudio && !mHasVideo) { return NO_INIT; @@ -182,12 +180,21 @@ status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs, int64_t nowUs) if (mAnchorTimeMediaUs < 0) { return NO_INIT; } + int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs; if (mPauseStartedTimeRealUs != -1) { positionUs -= (nowUs - mPauseStartedTimeRealUs); } + // limit position to the last queued media time (for video only stream + // position will be discrete as we don't know how long each frame lasts) + if (mAnchorMaxMediaUs >= 0 && !allowPastQueuedVideo) { + if (positionUs > mAnchorMaxMediaUs) { + positionUs = mAnchorMaxMediaUs; + } + } + if (positionUs < mAudioFirstAnchorTimeMediaUs) { positionUs = mAudioFirstAnchorTimeMediaUs; } @@ -217,10 +224,12 @@ void NuPlayer::Renderer::setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs) { } } -void NuPlayer::Renderer::setAnchorTime(int64_t mediaUs, int64_t realUs, bool resume) { +void NuPlayer::Renderer::setAnchorTime( + int64_t mediaUs, int64_t realUs, int64_t numFramesWritten, bool resume) { Mutex::Autolock autoLock(mTimeLock); mAnchorTimeMediaUs = mediaUs; mAnchorTimeRealUs = realUs; + mAnchorNumFramesWritten = numFramesWritten; if (resume) { mPauseStartedTimeRealUs = -1; } @@ -241,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); @@ -255,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() { @@ -283,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)); @@ -406,6 +423,12 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) { break; } + case kWhatEnableOffloadAudio: + { + onEnableOffloadAudio(); + break; + } + case kWhatPause: { onPause(); @@ -541,7 +564,7 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { int64_t mediaTimeUs; CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6); - onNewAudioMediaTime(mediaTimeUs); + setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); } size_t copy = entry->mBuffer->size() - entry->mOffset; @@ -564,6 +587,14 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) { notifyIfMediaRenderingStarted(); } + if (mAudioFirstAnchorTimeMediaUs >= 0) { + int64_t nowUs = ALooper::GetNowUs(); + setAnchorTime(mAudioFirstAnchorTimeMediaUs, nowUs - getPlayedOutAudioDurationUs(nowUs)); + } + + // we don't know how much data we are queueing for offloaded tracks + mAnchorMaxMediaUs = -1; + if (hasEOS) { (new AMessage(kWhatStopAudioSink, id()))->post(); } @@ -607,6 +638,10 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { mAudioQueue.erase(mAudioQueue.begin()); entry = NULL; + // Need to stop the track here, because that will play out the last + // little bit at the end of the file. Otherwise short files won't play. + mAudioSink->stop(); + mNumFramesWritten = 0; return false; } @@ -624,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; @@ -663,6 +699,11 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { break; } } + mAnchorMaxMediaUs = + mAnchorTimeMediaUs + + (int64_t)(max((long long)mNumFramesWritten - mAnchorNumFramesWritten, 0LL) + * 1000LL * mAudioSink->msecsPerFrame()); + return !mAudioQueue.empty(); } @@ -674,7 +715,7 @@ int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) { int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) { int64_t currentPositionUs; - if (getCurrentPosition(¤tPositionUs, nowUs) != OK) { + if (getCurrentPosition(¤tPositionUs, nowUs, true /* allowPastQueuedVideo */) != OK) { // If failed to get current position, e.g. due to audio clock is not ready, then just // play out video immediately without delay. return nowUs; @@ -690,7 +731,8 @@ void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) { } setAudioFirstAnchorTimeIfNeeded(mediaTimeUs); int64_t nowUs = ALooper::GetNowUs(); - setAnchorTime(mediaTimeUs, nowUs + getPendingAudioPlayoutDurationUs(nowUs)); + setAnchorTime( + mediaTimeUs, nowUs + getPendingAudioPlayoutDurationUs(nowUs), mNumFramesWritten); } void NuPlayer::Renderer::postDrainVideoQueue() { @@ -729,10 +771,14 @@ void NuPlayer::Renderer::postDrainVideoQueue() { if (mAnchorTimeMediaUs < 0) { setAnchorTime(mediaTimeUs, nowUs); + mAnchorMaxMediaUs = mediaTimeUs; realTimeUs = nowUs; } else { realTimeUs = getRealTimeUs(mediaTimeUs, nowUs); } + if (!mHasAudio) { + mAnchorMaxMediaUs = mediaTimeUs + 100000; // smooth out videos >= 10fps + } // Heuristics to handle situation when media time changed without a // discontinuity. If we have not drained an audio buffer that was @@ -761,11 +807,6 @@ void NuPlayer::Renderer::postDrainVideoQueue() { ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); // post 2 display refreshes before rendering is due - // FIXME currently this increases power consumption, so unless frame-accurate - // AV sync is requested, post closer to required render time (at 0.63 vsyncs) - if (!sFrameAccurateAVsync) { - twoVsyncsUs >>= 4; - } msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0); mDrainVideoQueuePending = true; @@ -988,15 +1029,19 @@ void NuPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) { } void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { - int32_t audio; + int32_t audio, notifyComplete; CHECK(msg->findInt32("audio", &audio)); { Mutex::Autolock autoLock(mFlushLock); if (audio) { mFlushingAudio = false; + notifyComplete = mNotifyCompleteAudio; + mNotifyCompleteAudio = false; } else { mFlushingVideo = false; + notifyComplete = mNotifyCompleteVideo; + mNotifyCompleteVideo = false; } } @@ -1012,6 +1057,7 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { Mutex::Autolock autoLock(mLock); syncQueuesDone_l(); setPauseStartedTimeRealUs(-1); + setAnchorTime(-1, -1); } ALOGV("flushing %s", audio ? "audio" : "video"); @@ -1049,7 +1095,10 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { } mVideoSampleReceived = false; - notifyFlushComplete(audio); + + if (notifyComplete) { + notifyFlushComplete(audio); + } } void NuPlayer::Renderer::flushQueue(List<QueueEntry> *queue) { @@ -1103,6 +1152,7 @@ void NuPlayer::Renderer::onAudioSinkChanged() { } CHECK(!mDrainAudioQueuePending); mNumFramesWritten = 0; + mAnchorNumFramesWritten = -1; uint32_t written; if (mAudioSink->getFramesWritten(&written) == OK) { mNumFramesWritten = written; @@ -1115,6 +1165,12 @@ void NuPlayer::Renderer::onDisableOffloadAudio() { ++mAudioQueueGeneration; } +void NuPlayer::Renderer::onEnableOffloadAudio() { + Mutex::Autolock autoLock(mLock); + mFlags |= FLAG_OFFLOAD_AUDIO; + ++mAudioQueueGeneration; +} + void NuPlayer::Renderer::onPause() { if (mPaused) { ALOGW("Renderer::onPause() called while already paused!"); @@ -1142,8 +1198,6 @@ void NuPlayer::Renderer::onPause() { } void NuPlayer::Renderer::onResume() { - readProperties(); - if (!mPaused) { return; } @@ -1158,7 +1212,8 @@ void NuPlayer::Renderer::onResume() { if (mPauseStartedTimeRealUs != -1) { int64_t newAnchorRealUs = mAnchorTimeRealUs + ALooper::GetNowUs() - mPauseStartedTimeRealUs; - setAnchorTime(mAnchorTimeMediaUs, newAnchorRealUs, true /* resume */); + setAnchorTime( + mAnchorTimeMediaUs, newAnchorRealUs, mAnchorNumFramesWritten, true /* resume */); } if (!mAudioQueue.empty()) { @@ -1276,7 +1331,7 @@ void NuPlayer::Renderer::cancelAudioOffloadPauseTimeout() { } } -bool NuPlayer::Renderer::onOpenAudioSink( +status_t NuPlayer::Renderer::onOpenAudioSink( const sp<AMessage> &format, bool offloadOnly, bool hasVideo, @@ -1338,11 +1393,12 @@ 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"); - flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; - flags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER; + uint32_t offloadFlags = flags; + offloadFlags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; + offloadFlags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER; audioSinkChanged = true; mAudioSink->close(); err = mAudioSink->open( @@ -1353,7 +1409,7 @@ bool NuPlayer::Renderer::onOpenAudioSink( 8 /* bufferCount */, &NuPlayer::Renderer::AudioSinkCallback, this, - (audio_output_flags_t)flags, + (audio_output_flags_t)offloadFlags, &offloadInfo); if (err == OK) { @@ -1377,13 +1433,13 @@ bool NuPlayer::Renderer::onOpenAudioSink( } } if (!offloadOnly && !offloadingAudio()) { - flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; ALOGV("openAudioSink: open AudioSink in NON-offload mode"); - + uint32_t pcmFlags = flags; + pcmFlags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; audioSinkChanged = true; mAudioSink->close(); mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER; - CHECK_EQ(mAudioSink->open( + status_t err = mAudioSink->open( sampleRate, numChannels, (audio_channel_mask_t)channelMask, @@ -1391,15 +1447,20 @@ bool NuPlayer::Renderer::onOpenAudioSink( 8 /* bufferCount */, NULL, NULL, - (audio_output_flags_t)flags), - (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) { onAudioSinkChanged(); } - - return offloadingAudio(); + if (offloadingAudio()) { + mAudioOffloadTornDown = false; + } + return OK; } void NuPlayer::Renderer::onCloseAudioSink() { |