From 7f5a4e3e2e64b53e243a36c711551c0a361d1554 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 20 Aug 2014 09:44:44 -0700 Subject: Fix NuPlayer deadlock Mutexes can't be locked recursively. This would cause a seek in the prepared state to deadlock Bug: 14057920 Change-Id: Ifb5e25f24450b7e5f71611a8ee2bdba45dba70a7 --- .../nuplayer/NuPlayerDriver.cpp | 33 +++++++++++++--------- .../nuplayer/NuPlayerDriver.h | 1 + 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 140e1ae..e11f40e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -227,7 +227,7 @@ status_t NuPlayerDriver::start() { if (mStartupSeekTimeUs >= 0) { if (mStartupSeekTimeUs == 0) { - notifySeekComplete(); + notifySeekComplete_l(); } else { mPlayer->seekToAsync(mStartupSeekTimeUs); } @@ -320,7 +320,7 @@ status_t NuPlayerDriver::seekTo(int msec) { // pretend that the seek completed. It will actually happen when starting playback. // TODO: actually perform the seek here, so the player is ready to go at the new // location - notifySeekComplete(); + notifySeekComplete_l(); break; } @@ -525,23 +525,28 @@ void NuPlayerDriver::notifyPosition(int64_t positionUs) { } void NuPlayerDriver::notifySeekComplete() { + Mutex::Autolock autoLock(mLock); + notifySeekComplete_l(); +} + +void NuPlayerDriver::notifySeekComplete_l() { bool wasSeeking = true; - { - Mutex::Autolock autoLock(mLock); - if (mState == STATE_STOPPED_AND_PREPARING) { - wasSeeking = false; - mState = STATE_STOPPED_AND_PREPARED; - mCondition.broadcast(); - if (!mIsAsyncPrepare) { - // if we are preparing synchronously, no need to notify listener - return; - } - } else if (mState == STATE_STOPPED) { - // no need to notify listener + if (mState == STATE_STOPPED_AND_PREPARING) { + wasSeeking = false; + mState = STATE_STOPPED_AND_PREPARED; + mCondition.broadcast(); + if (!mIsAsyncPrepare) { + // if we are preparing synchronously, no need to notify listener return; } + } else if (mState == STATE_STOPPED) { + // no need to notify listener + return; } + // note: notifyListener called with lock held + mLock.unlock(); notifyListener(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); + mLock.lock(); } void NuPlayerDriver::notifyFrameStats( diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index f520395..a006d8f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -69,6 +69,7 @@ struct NuPlayerDriver : public MediaPlayerInterface { void notifyDuration(int64_t durationUs); void notifyPosition(int64_t positionUs); void notifySeekComplete(); + void notifySeekComplete_l(); void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped); void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL); void notifyFlagsChanged(uint32_t flags); -- cgit v1.1 From afcb794a3d837764f0e1ce036796b4f1c5202190 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 20 Aug 2014 12:46:47 -0700 Subject: Fix typo in comment Bug: 14057920 Change-Id: I51c4d47b9e175ef789ed3c51d59c9eda77edc1e0 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index e11f40e..8a63cfe 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -543,7 +543,7 @@ void NuPlayerDriver::notifySeekComplete_l() { // no need to notify listener return; } - // note: notifyListener called with lock held + // note: notifyListener called with lock released mLock.unlock(); notifyListener(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED); mLock.lock(); -- cgit v1.1 From 5746c86c90cd65be2b79d94a53877d83292bac81 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Thu, 21 Aug 2014 13:41:42 -0700 Subject: camera2: Fix CameraUtils orientation for front camera. Bug: 16637957 Change-Id: If6d213794a92eb60b8a333546670ca868b75e5fc --- camera/CameraUtils.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp index 1ff63ab..04244ac 100644 --- a/camera/CameraUtils.cpp +++ b/camera/CameraUtils.cpp @@ -73,23 +73,23 @@ status_t CameraUtils::getRotationTransform(const CameraMetadata& staticInfo, return INVALID_OPERATION; } } else { - // Front camera needs to be horizontally flipped for - // mirror-like behavior. - // Note: Flips are applied before rotates. + // Front camera needs to be horizontally flipped for mirror-like behavior. + // Note: Flips are applied before rotates; using XOR here as some of these flags are + // composed in terms of other flip/rotation flags, and are not bitwise-ORable. switch (orientation) { case 0: flags = NATIVE_WINDOW_TRANSFORM_FLIP_H; break; case 90: - flags = NATIVE_WINDOW_TRANSFORM_FLIP_H | + flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^ NATIVE_WINDOW_TRANSFORM_ROT_270; break; case 180: - flags = NATIVE_WINDOW_TRANSFORM_FLIP_H | + flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^ NATIVE_WINDOW_TRANSFORM_ROT_180; break; case 270: - flags = NATIVE_WINDOW_TRANSFORM_FLIP_H | + flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^ NATIVE_WINDOW_TRANSFORM_ROT_90; break; -- cgit v1.1 From 43e36e9ec905f8bc0bbc7afc495e3a298c168a66 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 19 Aug 2014 18:07:08 -0700 Subject: print warning if offset != buffer size Bug: 17110981 Change-Id: Iacceca203372f4c06ff5ef7ce98edd5554727b64 --- media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp index 76f8f54..7eb6542 100644 --- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp @@ -358,6 +358,11 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( CopyTimes(accessUnit, buffer); mPackets.push_back(accessUnit); } + + if (offset != buffer->size()) { + ALOGW("potentially malformed packet (offset %d, size %d)", + offset, buffer->size()); + } } queue->erase(queue->begin()); -- cgit v1.1 From fe6ac9fee19c932f074c48eae9f119211021fc8c Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Wed, 20 Aug 2014 17:37:59 -0700 Subject: Fix SoundPool and MediaPlayerService buffer overflow Overflow occurs when SoundPool sample tracks cannot fit in the MediaPlayerService AudioCache buffer. Unnecessary decoding occurred with AwesomePlayer and an assert failure occurred with NuPlayer. NuPlayerRenderer is also tweaked to handle the latter case. Bug: 17122639 Change-Id: I4d25d3e2c0c62e36a91da6bf969edabddc2ebbb0 --- media/libmediaplayerservice/MediaPlayerService.cpp | 31 ++++++++++++++++--- media/libmediaplayerservice/MediaPlayerService.h | 3 +- .../nuplayer/NuPlayerRenderer.cpp | 36 +++++++++++++++++----- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 2c48306..b5bd988 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1798,7 +1798,9 @@ ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) //ALOGV("write(%p, %u)", buffer, size); if (mTrack != 0) { ssize_t ret = mTrack->write(buffer, size); - mBytesWritten += ret; + if (ret >= 0) { + mBytesWritten += ret; + } return ret; } return NO_INIT; @@ -1945,7 +1947,7 @@ uint32_t MediaPlayerService::AudioOutput::getSampleRate() const #define LOG_TAG "AudioCache" MediaPlayerService::AudioCache::AudioCache(const sp& heap) : mHeap(heap), mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0), - mError(NO_ERROR), mCommandComplete(false) + mFrameSize(1), mError(NO_ERROR), mCommandComplete(false) { } @@ -1962,14 +1964,14 @@ float MediaPlayerService::AudioCache::msecsPerFrame() const status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position) const { if (position == 0) return BAD_VALUE; - *position = mSize; + *position = mSize / mFrameSize; return NO_ERROR; } status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const { if (written == 0) return BAD_VALUE; - *written = mSize; + *written = mSize / mFrameSize; return NO_ERROR; } @@ -2031,6 +2033,8 @@ bool CallbackThread::threadLoop() { if (actualSize > 0) { sink->write(mBuffer, actualSize); + // Could return false on sink->write() error or short count. + // Not necessarily appropriate but would work for AudioCache behavior. } return true; @@ -2053,6 +2057,9 @@ status_t MediaPlayerService::AudioCache::open( mChannelCount = (uint16_t)channelCount; mFormat = format; mMsecsPerFrame = 1.e3 / (float) sampleRate; + mFrameSize = audio_is_linear_pcm(mFormat) + ? mChannelCount * audio_bytes_per_sample(mFormat) : 1; + mFrameCount = mHeap->getSize() / mFrameSize; if (cb != NULL) { mCallbackThread = new CallbackThread(this, cb, cookie); @@ -2082,12 +2089,26 @@ ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size) if (p == NULL) return NO_INIT; p += mSize; ALOGV("memcpy(%p, %p, %u)", p, buffer, size); - if (mSize + size > mHeap->getSize()) { + + bool overflow = mSize + size > mHeap->getSize(); + if (overflow) { ALOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize()); size = mHeap->getSize() - mSize; } + size -= size % mFrameSize; // consume only integral amounts of frame size memcpy(p, buffer, size); mSize += size; + + if (overflow) { + // Signal heap filled here (last frame may be truncated). + // After this point, no more data should be written as the + // heap is filled and the AudioCache should be effectively + // immutable with respect to future writes. + // + // It is thus safe for another thread to read the AudioCache. + mCommandComplete = true; + mSignal.signal(); + } return size; } diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 406e3f6..4fe7075 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -194,7 +194,7 @@ class MediaPlayerService : public BnMediaPlayerService virtual ssize_t bufferSize() const { return frameSize() * mFrameCount; } virtual ssize_t frameCount() const { return mFrameCount; } virtual ssize_t channelCount() const { return (ssize_t)mChannelCount; } - virtual ssize_t frameSize() const { return ssize_t(mChannelCount * ((mFormat == AUDIO_FORMAT_PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); } + virtual ssize_t frameSize() const { return (ssize_t)mFrameSize; } virtual uint32_t latency() const; virtual float msecsPerFrame() const; virtual status_t getPosition(uint32_t *position) const; @@ -244,6 +244,7 @@ class MediaPlayerService : public BnMediaPlayerService ssize_t mFrameCount; uint32_t mSampleRate; uint32_t mSize; + size_t mFrameSize; int mError; bool mCommandComplete; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 1213a18..a3c976d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -448,11 +448,13 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { copy = numBytesAvailableToWrite; } - CHECK_EQ(mAudioSink->write( - entry->mBuffer->data() + entry->mOffset, copy), - (ssize_t)copy); + 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); + } - entry->mOffset += copy; + entry->mOffset += written; if (entry->mOffset == entry->mBuffer->size()) { entry->mNotifyConsumed->post(); mAudioQueue.erase(mAudioQueue.begin()); @@ -460,13 +462,33 @@ bool NuPlayer::Renderer::onDrainAudioQueue() { entry = NULL; } - numBytesAvailableToWrite -= copy; - size_t copiedFrames = copy / mAudioSink->frameSize(); + numBytesAvailableToWrite -= written; + size_t copiedFrames = written / mAudioSink->frameSize(); mNumFramesWritten += copiedFrames; notifyIfMediaRenderingStarted(); - } + if (written != (ssize_t)copy) { + // A short count was received from AudioSink::write() + // + // AudioSink write should block until exactly the number of bytes are delivered. + // But it may return with a short count (without an error) when: + // + // 1) Size to be copied is not a multiple of the frame size. We consider this fatal. + // 2) AudioSink is an AudioCache for data retrieval, and the AudioCache is exceeded. + + // (Case 1) + // Must be a multiple of the frame size. If it is not a multiple of a frame size, it + // needs to fail, as we should not carry over fractional frames between calls. + CHECK_EQ(copy % mAudioSink->frameSize(), 0); + + // (Case 2) + // Return early to the caller. + // Beware of calling immediately again as this may busy-loop if you are not careful. + ALOGW("AudioSink write short frame count %zd < %zu", written, copy); + break; + } + } notifyPosition(); return !mAudioQueue.empty(); -- cgit v1.1 From 615fb231ac0c750af41d35dfe13e752630fea00b Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 20 Aug 2014 13:09:58 -0700 Subject: move cache prefill to GenericSource's message handler This allows prepareAsync to be terminated by reset promptly. It also makes it easier to do buffer update as GenericSource can access the cache status now. Bug: 16892748 Bug: 17182378 Change-Id: Ia55c04a810fd805041cb2025f6739afa5120b5ed --- include/media/stagefright/DataSource.h | 6 +- .../nuplayer/GenericSource.cpp | 147 +++++++++++++++++---- .../libmediaplayerservice/nuplayer/GenericSource.h | 16 ++- media/libstagefright/DataSource.cpp | 77 +---------- 4 files changed, 143 insertions(+), 103 deletions(-) diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h index 3fb9e36..8000e84 100644 --- a/include/media/stagefright/DataSource.h +++ b/include/media/stagefright/DataSource.h @@ -48,7 +48,7 @@ public: const sp &httpService, const char *uri, const KeyedVector *headers = NULL, - AString *sniffedMIME = NULL); + String8 *contentType = NULL); DataSource() {} @@ -102,10 +102,6 @@ protected: virtual ~DataSource() {} private: - enum { - kDefaultMetaSize = 200000, - }; - static Mutex gSnifferMutex; static List gSniffers; static bool gSniffersRegistered; diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 76e1d54..3706117 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -32,6 +32,7 @@ #include #include #include +#include "../../libstagefright/include/NuCachedSource2.h" #include "../../libstagefright/include/WVMExtractor.h" namespace android { @@ -47,7 +48,8 @@ NuPlayer::GenericSource::GenericSource( mAudioIsVorbis(false), mIsWidevine(false), mUIDValid(uidValid), - mUID(uid) { + mUID(uid), + mMetaDataSize(-1ll) { resetDataSource(); DataSource::RegisterDefaultSniffers(); } @@ -92,18 +94,18 @@ status_t NuPlayer::GenericSource::setDataSource( return OK; } -status_t NuPlayer::GenericSource::initFromDataSource( - const sp &dataSource, - const char* mime) { +status_t NuPlayer::GenericSource::initFromDataSource() { sp extractor; + CHECK(mDataSource != NULL); + if (mIsWidevine) { String8 mimeType; float confidence; sp dummy; bool success; - success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); + success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy); if (!success || strcasecmp( mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { @@ -111,14 +113,15 @@ status_t NuPlayer::GenericSource::initFromDataSource( return UNKNOWN_ERROR; } - sp wvmExtractor = new WVMExtractor(dataSource); + sp wvmExtractor = new WVMExtractor(mDataSource); wvmExtractor->setAdaptiveStreamingMode(true); if (mUIDValid) { wvmExtractor->setUID(mUID); } extractor = wvmExtractor; } else { - extractor = MediaExtractor::Create(dataSource, mime); + extractor = MediaExtractor::Create(mDataSource, + mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str()); } if (extractor == NULL) { @@ -213,34 +216,49 @@ void NuPlayer::GenericSource::prepareAsync() { void NuPlayer::GenericSource::onPrepareAsync() { // delayed data source creation - AString sniffedMIME; - sp dataSource; + if (mDataSource == NULL) { + if (!mUri.empty()) { + mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11); - if (!mUri.empty()) { - mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11); + mDataSource = DataSource::CreateFromURI( + mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType); + } else { + // set to false first, if the extractor + // comes back as secure, set it to true then. + mIsWidevine = false; - dataSource = DataSource::CreateFromURI( - mHTTPService, mUri.c_str(), &mUriHeaders, &sniffedMIME); - } else { - // set to false first, if the extractor - // comes back as secure, set it to true then. - mIsWidevine = false; + mDataSource = new FileSource(mFd, mOffset, mLength); + } + + if (mDataSource == NULL) { + ALOGE("Failed to create data source!"); + notifyPreparedAndCleanup(UNKNOWN_ERROR); + return; + } - dataSource = new FileSource(mFd, mOffset, mLength); + if (mDataSource->flags() & DataSource::kIsCachingDataSource) { + mCachedSource = static_cast(mDataSource.get()); + } } - if (dataSource == NULL) { - ALOGE("Failed to create data source!"); - notifyPrepared(UNKNOWN_ERROR); + // check initial caching status + status_t err = prefillCacheIfNecessary(); + if (err != OK) { + if (err == -EAGAIN) { + (new AMessage(kWhatPrepareAsync, id()))->post(200000); + } else { + ALOGE("Failed to prefill data cache!"); + notifyPreparedAndCleanup(UNKNOWN_ERROR); + } return; } - status_t err = initFromDataSource( - dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); + // init extrator from data source + err = initFromDataSource(); if (err != OK) { ALOGE("Failed to init from data source!"); - notifyPrepared(err); + notifyPreparedAndCleanup(err); return; } @@ -258,6 +276,87 @@ void NuPlayer::GenericSource::onPrepareAsync() { notifyPrepared(); } +void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { + if (err != OK) { + mMetaDataSize = -1ll; + mContentType = ""; + mSniffedMIME = ""; + mDataSource.clear(); + mCachedSource.clear(); + } + notifyPrepared(err); +} + +status_t NuPlayer::GenericSource::prefillCacheIfNecessary() { + CHECK(mDataSource != NULL); + + if (mCachedSource == NULL) { + // no prefill if the data source is not cached + return OK; + } + + // We're not doing this for streams that appear to be audio-only + // streams to ensure that even low bandwidth streams start + // playing back fairly instantly. + if (!strncasecmp(mContentType.string(), "audio/", 6)) { + return OK; + } + + // We're going to prefill the cache before trying to instantiate + // the extractor below, as the latter is an operation that otherwise + // could block on the datasource for a significant amount of time. + // During that time we'd be unable to abort the preparation phase + // without this prefill. + + // Initially make sure we have at least 192 KB for the sniff + // to complete without blocking. + static const size_t kMinBytesForSniffing = 192 * 1024; + static const size_t kDefaultMetaSize = 200000; + + status_t finalStatus; + + size_t cachedDataRemaining = + mCachedSource->approxDataRemaining(&finalStatus); + + if (finalStatus != OK || (mMetaDataSize >= 0 + && (off64_t)cachedDataRemaining >= mMetaDataSize)) { + ALOGV("stop caching, status %d, " + "metaDataSize %lld, cachedDataRemaining %zu", + finalStatus, mMetaDataSize, cachedDataRemaining); + return OK; + } + + ALOGV("now cached %zu bytes of data", cachedDataRemaining); + + if (mMetaDataSize < 0 + && cachedDataRemaining >= kMinBytesForSniffing) { + String8 tmp; + float confidence; + sp meta; + if (!mCachedSource->sniff(&tmp, &confidence, &meta)) { + return UNKNOWN_ERROR; + } + + // We successfully identified the file's extractor to + // be, remember this mime type so we don't have to + // sniff it again when we call MediaExtractor::Create() + mSniffedMIME = tmp.string(); + + if (meta == NULL + || !meta->findInt64("meta-data-size", + reinterpret_cast(&mMetaDataSize))) { + mMetaDataSize = kDefaultMetaSize; + } + + if (mMetaDataSize < 0ll) { + ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize); + return UNKNOWN_ERROR; + } + } + + return -EAGAIN; +} + void NuPlayer::GenericSource::start() { ALOGI("start"); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index d3081de..946307c 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -33,6 +33,7 @@ struct DataSource; struct IMediaHTTPService; struct MediaSource; class MediaBuffer; +struct NuCachedSource2; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource(const sp ¬ify, bool uidValid, uid_t uid); @@ -105,14 +106,21 @@ private: int64_t mOffset; int64_t mLength; - sp mLooper; + sp mDataSource; + sp mCachedSource; + String8 mContentType; + AString mSniffedMIME; + off64_t mMetaDataSize; + sp mLooper; void resetDataSource(); - status_t initFromDataSource( - const sp &dataSource, - const char *mime); + status_t initFromDataSource(); + + status_t prefillCacheIfNecessary(); + + void notifyPreparedAndCleanup(status_t err); void onPrepareAsync(); diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 008da5a..9d6fd78 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -186,9 +186,9 @@ sp DataSource::CreateFromURI( const sp &httpService, const char *uri, const KeyedVector *headers, - AString *sniffedMIME) { - if (sniffedMIME != NULL) { - *sniffedMIME = ""; + String8 *contentType) { + if (contentType != NULL) { + *contentType = ""; } bool isWidevine = !strncasecmp("widevine://", uri, 11); @@ -226,77 +226,14 @@ sp DataSource::CreateFromURI( } if (!isWidevine) { - String8 contentType = httpSource->getMIMEType(); + if (contentType != NULL) { + *contentType = httpSource->getMIMEType(); + } - sp cachedSource = new NuCachedSource2( + source = new NuCachedSource2( httpSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); - - if (strncasecmp(contentType.string(), "audio/", 6)) { - // We're not doing this for streams that appear to be audio-only - // streams to ensure that even low bandwidth streams start - // playing back fairly instantly. - - // We're going to prefill the cache before trying to instantiate - // the extractor below, as the latter is an operation that otherwise - // could block on the datasource for a significant amount of time. - // During that time we'd be unable to abort the preparation phase - // without this prefill. - - // Initially make sure we have at least 192 KB for the sniff - // to complete without blocking. - static const size_t kMinBytesForSniffing = 192 * 1024; - - off64_t metaDataSize = -1ll; - for (;;) { - status_t finalStatus; - size_t cachedDataRemaining = - cachedSource->approxDataRemaining(&finalStatus); - - if (finalStatus != OK || (metaDataSize >= 0 - && (off64_t)cachedDataRemaining >= metaDataSize)) { - ALOGV("stop caching, status %d, " - "metaDataSize %lld, cachedDataRemaining %zu", - finalStatus, metaDataSize, cachedDataRemaining); - break; - } - - ALOGV("now cached %zu bytes of data", cachedDataRemaining); - - if (metaDataSize < 0 - && cachedDataRemaining >= kMinBytesForSniffing) { - String8 tmp; - float confidence; - sp meta; - if (!cachedSource->sniff(&tmp, &confidence, &meta)) { - return NULL; - } - - // We successfully identified the file's extractor to - // be, remember this mime type so we don't have to - // sniff it again when we call MediaExtractor::Create() - if (sniffedMIME != NULL) { - *sniffedMIME = tmp.string(); - } - - if (meta == NULL - || !meta->findInt64("meta-data-size", - reinterpret_cast(&metaDataSize))) { - metaDataSize = kDefaultMetaSize; - } - - if (metaDataSize < 0ll) { - ALOGE("invalid metaDataSize = %lld bytes", metaDataSize); - return NULL; - } - } - - usleep(200000); - } - } - - source = cachedSource; } else { // We do not want that prefetching, caching, datasource wrapper // in the widevine:// case. -- cgit v1.1 From 8ba2a6ec5c50e99c295309d93fd650ded2eb3d85 Mon Sep 17 00:00:00 2001 From: Rachad Alao Date: Mon, 25 Aug 2014 21:46:34 +0000 Subject: Revert "disable AwesomePlayer for Ogg vorbis" Temporarily revert commit 9b48f5d780757ffb81709df3633d06b62edaf39f as a workaround for b/17173673 Bug: 17173673 Change-Id: Iec52289e77485a58ce28cc515d6a5b8e7b2d328a --- media/libmediaplayerservice/MediaPlayerFactory.cpp | 25 ++++++++++------------ media/libmediaplayerservice/MediaPlayerFactory.h | 1 + 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp index 3e0fc0d..dacb144 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -60,7 +60,7 @@ status_t MediaPlayerFactory::registerFactory_l(IFactory* factory, return OK; } -static player_type getDefaultPlayerType() { +player_type MediaPlayerFactory::getDefaultPlayerType() { char value[PROPERTY_VALUE_MAX]; if (property_get("media.stagefright.use-awesome", value, NULL) && (!strcmp("1", value) || !strcasecmp("true", value))) { @@ -181,19 +181,16 @@ class StagefrightPlayerFactory : int64_t offset, int64_t /*length*/, float /*curScore*/) { - if (getDefaultPlayerType() - == STAGEFRIGHT_PLAYER) { - char buf[20]; - lseek(fd, offset, SEEK_SET); - read(fd, buf, sizeof(buf)); - lseek(fd, offset, SEEK_SET); - - uint32_t ident = *((uint32_t*)buf); - - // Ogg vorbis? - if (ident == 0x5367674f) // 'OggS' - return 1.0; - } + char buf[20]; + lseek(fd, offset, SEEK_SET); + read(fd, buf, sizeof(buf)); + lseek(fd, offset, SEEK_SET); + + uint32_t ident = *((uint32_t*)buf); + + // Ogg vorbis? + if (ident == 0x5367674f) // 'OggS' + return 1.0; return 0.0; } diff --git a/media/libmediaplayerservice/MediaPlayerFactory.h b/media/libmediaplayerservice/MediaPlayerFactory.h index 55ff918..5ddde19 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.h +++ b/media/libmediaplayerservice/MediaPlayerFactory.h @@ -71,6 +71,7 @@ class MediaPlayerFactory { static status_t registerFactory_l(IFactory* factory, player_type type); + static player_type getDefaultPlayerType(); static Mutex sLock; static tFactoryMap sFactoryMap; -- cgit v1.1 From 9a8b629ad56f97e0178aa7352bafd66ec6b0ced3 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 26 Aug 2014 09:56:52 -0700 Subject: do string compare with mime immediately after we get the value Bug: 17210803 Change-Id: I4d20dd4b95d18251c18a371bd8f89b1320b38879 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index cdb7e69..f0f4e45 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -141,13 +141,17 @@ status_t NuPlayer::GenericSource::initFromDataSource() { int32_t totalBitrate = 0; for (size_t i = 0; i < extractor->countTracks(); ++i) { + sp track = extractor->getTrack(i); + sp meta = extractor->getTrackMetaData(i); const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); - sp track = extractor->getTrack(i); - + // Do the string compare immediately with "mime", + // we can't assume "mime" would stay valid after another + // extractor operation, some extractors might modify meta + // during getTrack() and make it invalid. if (!strncasecmp(mime, "audio/", 6)) { if (mAudioTrack.mSource == NULL) { mAudioTrack.mIndex = i; -- cgit v1.1 From 1c874b152291361fb5a05fc9da87aba664898fd5 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 26 Aug 2014 13:57:32 -0700 Subject: Fix SoundPool lockup NuPlayerDriver needs to update its internal state before calling its listener, so that when the listener calls back into NuPlayerDriver, NuPlayerDriver has the right state. Bug: 14057920 Change-Id: I224882c427f5e3c9d4bf96c5d68075e235062401 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 2f60072..c4bbcdf 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -287,8 +287,9 @@ status_t NuPlayerDriver::stop() { // fall through case STATE_PAUSED: + mState = STATE_STOPPED; notifyListener_l(MEDIA_STOPPED); - // fall through + break; case STATE_PREPARED: case STATE_STOPPED: @@ -314,6 +315,8 @@ status_t NuPlayerDriver::pause() { return OK; case STATE_RUNNING: + setPauseStartedTimeIfNeeded(); + mState = STATE_PAUSED; notifyListener_l(MEDIA_PAUSED); mPlayer->pause(); break; @@ -322,9 +325,6 @@ status_t NuPlayerDriver::pause() { return INVALID_OPERATION; } - setPauseStartedTimeIfNeeded(); - mState = STATE_PAUSED; - return OK; } @@ -675,15 +675,17 @@ void NuPlayerDriver::notifyPrepareCompleted(status_t err) { mAsyncResult = err; if (err == OK) { + // update state before notifying client, so that if client calls back into NuPlayerDriver + // in response, NuPlayerDriver has the right state + mState = STATE_PREPARED; if (mIsAsyncPrepare) { notifyListener_l(MEDIA_PREPARED); } - mState = STATE_PREPARED; } else { + mState = STATE_UNPREPARED; if (mIsAsyncPrepare) { notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); } - mState = STATE_UNPREPARED; } mCondition.broadcast(); -- cgit v1.1 From 4789dea53f9e4404762cbeceafa7b54cf67dc77a Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 25 Aug 2014 15:58:39 -0700 Subject: Fix memory leak in getConnectionState Turns out having an sp<> point at the containing object doesn't really work so well. Bug: 17210991 Change-Id: I4bcb0c38adffc574d661f0772583357868f6c5b4 --- services/audiopolicy/AudioPolicyManager.cpp | 16 +++++++--------- services/audiopolicy/AudioPolicyManager.h | 5 ++++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 14fdec5..b643eac 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -3874,7 +3874,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate if (((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) || (((txDevice & availablePrimaryInputDevices() & ~AUDIO_DEVICE_BIT_IN) != 0) && - (hwOutputDesc->mAudioPort->mModule->mHalVersion < + (hwOutputDesc->getAudioPort()->mModule->mHalVersion < AUDIO_DEVICE_API_VERSION_3_0))) { availableOutputDeviceTypes = availablePrimaryOutputDevices(); } @@ -5070,7 +5070,6 @@ AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor( mStrategyMutedByDevice[i] = false; } if (profile != NULL) { - mAudioPort = profile; mFlags = profile->mFlags; mSamplingRate = profile->pickSamplingRate(); mFormat = profile->pickFormat(); @@ -5253,7 +5252,6 @@ AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sppickSamplingRate(); mFormat = profile->pickFormat(); mChannelMask = profile->pickChannelMask(); @@ -6273,33 +6271,34 @@ status_t AudioPolicyManager::AudioPortConfig::applyAudioPortConfig( localBackupConfig.config_mask = config->config_mask; toAudioPortConfig(&localBackupConfig); - if (mAudioPort == 0) { + sp audioport = getAudioPort(); + if (audioport == 0) { status = NO_INIT; goto exit; } if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) { - status = mAudioPort->checkExactSamplingRate(config->sample_rate); + status = audioport->checkExactSamplingRate(config->sample_rate); if (status != NO_ERROR) { goto exit; } mSamplingRate = config->sample_rate; } if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) { - status = mAudioPort->checkExactChannelMask(config->channel_mask); + status = audioport->checkExactChannelMask(config->channel_mask); if (status != NO_ERROR) { goto exit; } mChannelMask = config->channel_mask; } if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) { - status = mAudioPort->checkFormat(config->format); + status = audioport->checkFormat(config->format); if (status != NO_ERROR) { goto exit; } mFormat = config->format; } if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) { - status = mAudioPort->checkGain(&config->gain, config->gain.index); + status = audioport->checkGain(&config->gain, config->gain.index); if (status != NO_ERROR) { goto exit; } @@ -6486,7 +6485,6 @@ AudioPolicyManager::DeviceDescriptor::DeviceDescriptor(const String8& name, audi NULL), mDeviceType(type), mAddress(""), mId(0) { - mAudioPort = this; if (mGains.size() > 0) { mGains[0]->getDefaultConfig(&mGain); } diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index e3e3172..6712eb7 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -297,7 +297,7 @@ protected: struct audio_port_config *backupConfig = NULL); virtual void toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig = NULL) const = 0; - sp mAudioPort; + virtual sp getAudioPort() const = 0; uint32_t mSamplingRate; audio_format_t mFormat; audio_channel_mask_t mChannelMask; @@ -330,6 +330,7 @@ protected: bool equals(const sp& other) const; virtual void toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig = NULL) const; + virtual sp getAudioPort() const { return (AudioPort*) this; } virtual void toAudioPort(struct audio_port *port) const; @@ -462,6 +463,7 @@ protected: virtual void toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig = NULL) const; + virtual sp getAudioPort() const { return mProfile; } void toAudioPort(struct audio_port *port) const; audio_port_handle_t mId; @@ -506,6 +508,7 @@ protected: virtual void toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig = NULL) const; + virtual sp getAudioPort() const { return mProfile; } void toAudioPort(struct audio_port *port) const; }; -- cgit v1.1 From 638794db70e692a0f5a6094809be0deedc0f94f4 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Wed, 27 Aug 2014 15:50:25 -0700 Subject: Camera API1: Fix ZSLProcessor3 deadlock ZSLProcessor3 shouldn't acquire mInputMutex in onBufferReleased call for output buffers, because the caller (Camera3Stream::returnBuffer) holds the camera3 stream lock already. This could cause deadlock for ZSL reprocess request as it holds the ZSLProcessor3 input lock and try to acquire camera3 stream lock to submit the request. Bug: 17299038 Change-Id: I6a7bf8ebd7c2064852358c655f3a3e9a67769213 --- services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp index b388079..3999047 100644 --- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp +++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp @@ -554,13 +554,15 @@ void ZslProcessor3::onBufferAcquired(const BufferInfo& /*bufferInfo*/) { } void ZslProcessor3::onBufferReleased(const BufferInfo& bufferInfo) { - Mutex::Autolock l(mInputMutex); // ignore output buffers if (bufferInfo.mOutput) { return; } + // Lock mutex only once we know this is an input buffer returned to avoid + // potential deadlock + Mutex::Autolock l(mInputMutex); // TODO: Verify that the buffer is in our queue by looking at timestamp // theoretically unnecessary unless we change the following assumptions: // -- only 1 buffer reprocessed at a time (which is the case now) -- cgit v1.1 From 9bd0ba2898bd0c0439ecd863433f9f9c3f0d5126 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 28 Aug 2014 10:49:08 -0700 Subject: Fix more potential deadlocks in ALooperRoster Bug: 17059501 Change-Id: I242f2859527bed2d6e275c27de94fb19f4dcdc28 --- .../media/stagefright/foundation/ALooperRoster.h | 2 -- media/libstagefright/foundation/ALooperRoster.cpp | 41 +++++++--------------- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h index 940fc55..4d76b64 100644 --- a/include/media/stagefright/foundation/ALooperRoster.h +++ b/include/media/stagefright/foundation/ALooperRoster.h @@ -56,8 +56,6 @@ private: KeyedVector > mReplies; - status_t postMessage_l(const sp &msg, int64_t delayUs); - DISALLOW_EVIL_CONSTRUCTORS(ALooperRoster); }; diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp index 0f44b52..e0dc768 100644 --- a/media/libstagefright/foundation/ALooperRoster.cpp +++ b/media/libstagefright/foundation/ALooperRoster.cpp @@ -99,35 +99,13 @@ void ALooperRoster::unregisterStaleHandlers() { status_t ALooperRoster::postMessage( const sp &msg, int64_t delayUs) { - Mutex::Autolock autoLock(mLock); - return postMessage_l(msg, delayUs); -} - -status_t ALooperRoster::postMessage_l( - const sp &msg, int64_t delayUs) { - ssize_t index = mHandlers.indexOfKey(msg->target()); - if (index < 0) { - ALOGW("failed to post message '%s'. Target handler not registered.", - msg->debugString().c_str()); - return -ENOENT; - } - - const HandlerInfo &info = mHandlers.valueAt(index); - - sp looper = info.mLooper.promote(); + sp looper = findLooper(msg->target()); if (looper == NULL) { - ALOGW("failed to post message. " - "Target handler %d still registered, but object gone.", - msg->target()); - - mHandlers.removeItemsAt(index); return -ENOENT; } - looper->post(msg, delayUs); - return OK; } @@ -181,18 +159,23 @@ sp ALooperRoster::findLooper(ALooper::handler_id handlerID) { status_t ALooperRoster::postAndAwaitResponse( const sp &msg, sp *response) { + sp looper = findLooper(msg->target()); + + if (looper == NULL) { + ALOGW("failed to post message. " + "Target handler %d still registered, but object gone.", + msg->target()); + response->clear(); + return -ENOENT; + } + Mutex::Autolock autoLock(mLock); uint32_t replyID = mNextReplyID++; msg->setInt32("replyID", replyID); - status_t err = postMessage_l(msg, 0 /* delayUs */); - - if (err != OK) { - response->clear(); - return err; - } + looper->post(msg, 0 /* delayUs */); ssize_t index; while ((index = mReplies.indexOfKey(replyID)) < 0) { -- cgit v1.1 From 16fdf7ec12dd8f7cefb70217ea080d0efe92e4c2 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 28 Aug 2014 12:40:34 -0700 Subject: Move stale handler cleanup to constructor This avoids the potential side effect of deleting more ALoopers inside the cleanup loop. Bug: 17059501 Change-Id: I41efaf490449b95fedfe01175f3b19067d50da24 --- media/libstagefright/foundation/ALooper.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp index ebf9d8d..88b1c92 100644 --- a/media/libstagefright/foundation/ALooper.cpp +++ b/media/libstagefright/foundation/ALooper.cpp @@ -68,14 +68,14 @@ int64_t ALooper::GetNowUs() { ALooper::ALooper() : mRunningLocally(false) { + // clean up stale AHandlers. Doing it here instead of in the destructor avoids + // the side effect of objects being deleted from the unregister function recursively. + gLooperRoster.unregisterStaleHandlers(); } ALooper::~ALooper() { stop(); - - // Since this looper is "dead" (or as good as dead by now), - // have ALooperRoster unregister any handlers still registered for it. - gLooperRoster.unregisterStaleHandlers(); + // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along } void ALooper::setName(const char *name) { -- cgit v1.1 From 002eda11d7bff5813fad13bd0ef3b6c4d4998157 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 9 Sep 2014 12:08:47 -0700 Subject: NuPlayer: check mSource before deferencing it. Bug: 17428608 Change-Id: I7b264d1288ed3c495434aedeeeef2fbfc3ca2f16 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index c8bf8f0..a44de98 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1244,7 +1244,8 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp &msg) { CHECK(msg->findMessage("reply", &reply)); if ((audio && mFlushingAudio != NONE) - || (!audio && mFlushingVideo != NONE)) { + || (!audio && mFlushingVideo != NONE) + || mSource == NULL) { reply->setInt32("err", INFO_DISCONTINUITY); reply->post(); return OK; -- cgit v1.1 From 95af55020ccbebdf5457165ea93244c9b0adfd4d Mon Sep 17 00:00:00 2001 From: Rachad Date: Tue, 9 Sep 2014 13:10:28 -0700 Subject: NuPlayer::Renderer::onPause() - Converted CHECK(!mPaused) to a warning. Bug: 17436451 Change-Id: I7e9e0c48bbdd8ab65c5f4a587699a28435bd03f4 --- media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index aad6e93..067784b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -893,8 +893,10 @@ void NuPlayer::Renderer::notifyPosition() { } void NuPlayer::Renderer::onPause() { - CHECK(!mPaused); - + if (mPaused) { + ALOGW("Renderer::onPause() called while already paused!"); + return; + } { Mutex::Autolock autoLock(mLock); ++mAudioQueueGeneration; -- cgit v1.1 From f3b5190f2aa659d498b1d31389b90a441fc879a7 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 9 Sep 2014 14:49:08 -0700 Subject: NuPlayer: make previous decoders obsolete when reset is done. Bug: 17428608 Change-Id: I724174d65f8e00bfecb51e6f690ae709ed2cf442 --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index a44de98..59766c8 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1833,6 +1833,9 @@ void NuPlayer::performReset() { ++mScanSourcesGeneration; mScanSourcesPending = false; + ++mAudioDecoderGeneration; + ++mVideoDecoderGeneration; + if (mRendererLooper != NULL) { if (mRenderer != NULL) { mRendererLooper->unregisterHandler(mRenderer->id()); -- cgit v1.1 From b6f9a21e7036e5619216faae902f005374bd8cad Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Tue, 9 Sep 2014 20:08:39 -0700 Subject: mediaplayer: limit number of outstanding buffer requests Bug: 14679336 Change-Id: I94a20ada30a9a25065329a85fc884d32d154d029 --- .../nuplayer/NuPlayerDecoderPassThrough.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp index c9be0dd..ab7906a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp @@ -115,9 +115,12 @@ void NuPlayer::DecoderPassThrough::requestABuffer() { notify->post(); mPendingBuffers++; - sp message = new AMessage(kWhatRequestABuffer, id()); - message->setInt32("generation", mBufferGeneration); - message->post(); + // pending buffers will already result in requestABuffer + if (mPendingBuffers < kMaxPendingBuffers) { + sp message = new AMessage(kWhatRequestABuffer, id()); + message->setInt32("generation", mBufferGeneration); + message->post(); + } return; } @@ -155,9 +158,7 @@ void android::NuPlayer::DecoderPassThrough::onInputBufferFilled( void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) { mPendingBuffers--; mCachedBytes -= size; - sp message = new AMessage(kWhatRequestABuffer, id()); - message->setInt32("generation", mBufferGeneration); - message->post(); + requestABuffer(); } void NuPlayer::DecoderPassThrough::onFlush() { -- cgit v1.1 From c02ca4ca1e7597891bcf92f9294c83d928118cf9 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 10 Sep 2014 10:43:41 -0700 Subject: fix failure in MediaCodecTest#testException reset codec after failed configure() Bug: 17418876 Change-Id: I21ff8a0751dae6a164678015142e11d481403bed --- media/libstagefright/MediaCodec.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index fc2dd30..0bfc6e4 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -270,7 +270,20 @@ status_t MediaCodec::configure( } sp response; - return PostAndAwaitResponse(msg, &response); + status_t err = PostAndAwaitResponse(msg, &response); + + if (err != OK && err != INVALID_OPERATION) { + // MediaCodec now set state to UNINITIALIZED upon any fatal error. + // To maintain backward-compatibility, do a reset() to put codec + // back into INITIALIZED state. + // But don't reset if the err is INVALID_OPERATION, which means + // the configure failure is due to wrong state. + + ALOGE("configure failed with err 0x%08x, resetting...", err); + reset(); + } + + return err; } status_t MediaCodec::createInputSurface( -- cgit v1.1 From 5fc863a507d3e1171158e0d16ff0174fadf0ec04 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 10 Sep 2014 12:21:59 -0700 Subject: Revert "Fix AAC timestamps for multiple aac frames per input buffer" This reverts commit e086387c805311ac87904c3c4d6d4eb08d4b4ee2. (broke multichannel movie playback) Bug: 17454025 Change-Id: I95b82359f87f8beca66f35c34b7e125850a44747 --- media/libstagefright/codecs/aacdec/SoftAAC2.cpp | 317 ++++++++++-------------- media/libstagefright/codecs/aacdec/SoftAAC2.h | 5 +- 2 files changed, 128 insertions(+), 194 deletions(-) diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 6dd9b92..8b4dd6f 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -//#define LOG_NDEBUG 0 #define LOG_TAG "SoftAAC2" +//#define LOG_NDEBUG 0 #include #include "SoftAAC2.h" @@ -68,6 +68,7 @@ SoftAAC2::SoftAAC2( mOutputBufferCount(0), mSignalledError(false), mLastInHeader(NULL), + mCurrentInputTime(0), mOutputPortSettingsChange(NONE) { initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); @@ -609,24 +610,9 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL); return; } - - // insert buffer size and time stamp - mBufferSizes.add(inBufferLength[0]); - if (mLastInHeader != inHeader) { - mBufferTimestamps.add(inHeader->nTimeStamp); - mLastInHeader = inHeader; - } else { - int64_t currentTime = mBufferTimestamps.top(); - currentTime += mStreamInfo->aacSamplesPerFrame * - 1000000ll / mStreamInfo->sampleRate; - mBufferTimestamps.add(currentTime); - } } else { inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; inBufferLength[0] = inHeader->nFilledLen; - mLastInHeader = inHeader; - mBufferTimestamps.add(inHeader->nTimeStamp); - mBufferSizes.add(inHeader->nFilledLen); } // Fill and decode @@ -635,130 +621,136 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { INT prevSampleRate = mStreamInfo->sampleRate; INT prevNumChannels = mStreamInfo->numChannels; + if (inHeader != mLastInHeader) { + mLastInHeader = inHeader; + mCurrentInputTime = inHeader->nTimeStamp; + } else { + if (mStreamInfo->sampleRate) { + mCurrentInputTime += mStreamInfo->aacSamplesPerFrame * + 1000000ll / mStreamInfo->sampleRate; + } else { + ALOGW("no sample rate yet"); + } + } + mAnchorTimes.add(mCurrentInputTime); aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, bytesValid); - // run DRC check - mDrcWrap.submitStreamData(mStreamInfo); - mDrcWrap.update(); + // run DRC check + mDrcWrap.submitStreamData(mStreamInfo); + mDrcWrap.update(); - UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; - inHeader->nFilledLen -= inBufferUsedLength; - inHeader->nOffset += inBufferUsedLength; + AAC_DECODER_ERROR decoderErr = + aacDecoder_DecodeFrame(mAACDecoder, + tmpOutBuffer, + 2048 * MAX_CHANNEL_COUNT, + 0 /* flags */); - AAC_DECODER_ERROR decoderErr; - do { - int numconsumed = mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes; - decoderErr = aacDecoder_DecodeFrame(mAACDecoder, - tmpOutBuffer, - 2048 * MAX_CHANNEL_COUNT, - 0 /* flags */); + if (decoderErr != AAC_DEC_OK) { + ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); + } - numconsumed = (mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes) - numconsumed; - if (numconsumed != 0) { - mDecodedSizes.add(numconsumed); - } + if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { + ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } - if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { - break; - } + if (bytesValid[0] != 0) { + ALOGE("bytesValid[0] != 0 should never happen"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; + } - if (decoderErr != AAC_DEC_OK) { - ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr); - } + size_t numOutBytes = + mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; - if (bytesValid[0] != 0) { - ALOGE("bytesValid[0] != 0 should never happen"); + if (decoderErr == AAC_DEC_OK) { + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } + UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; + inHeader->nFilledLen -= inBufferUsedLength; + inHeader->nOffset += inBufferUsedLength; + } else { + ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); - size_t numOutBytes = - mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; - - if (decoderErr == AAC_DEC_OK) { - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } - } else { - ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr); - - memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow - - if (!outputDelayRingBufferPutSamples(tmpOutBuffer, - mStreamInfo->frameSize * mStreamInfo->numChannels)) { - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - return; - } + memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow - // Discard input buffer. - inHeader->nFilledLen = 0; + if (!outputDelayRingBufferPutSamples(tmpOutBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels)) { + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } - aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); + // Discard input buffer. + inHeader->nFilledLen = 0; + + aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); + + // fall through + } + + /* + * AAC+/eAAC+ streams can be signalled in two ways: either explicitly + * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual + * rate system and the sampling rate in the final output is actually + * doubled compared with the core AAC decoder sampling rate. + * + * Explicit signalling is done by explicitly defining SBR audio object + * type in the bitstream. Implicit signalling is done by embedding + * SBR content in AAC extension payload specific to SBR, and hence + * requires an AAC decoder to perform pre-checks on actual audio frames. + * + * Thus, we could not say for sure whether a stream is + * AAC+/eAAC+ until the first data frame is decoded. + */ + if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 + if (mStreamInfo->sampleRate != prevSampleRate || + mStreamInfo->numChannels != prevNumChannels) { + ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", + prevSampleRate, mStreamInfo->sampleRate, + prevNumChannels, mStreamInfo->numChannels); - // fall through - } + notify(OMX_EventPortSettingsChanged, 1, 0, NULL); + mOutputPortSettingsChange = AWAITING_DISABLED; - /* - * AAC+/eAAC+ streams can be signalled in two ways: either explicitly - * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual - * rate system and the sampling rate in the final output is actually - * doubled compared with the core AAC decoder sampling rate. - * - * Explicit signalling is done by explicitly defining SBR audio object - * type in the bitstream. Implicit signalling is done by embedding - * SBR content in AAC extension payload specific to SBR, and hence - * requires an AAC decoder to perform pre-checks on actual audio frames. - * - * Thus, we could not say for sure whether a stream is - * AAC+/eAAC+ until the first data frame is decoded. - */ - if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1 - if (mStreamInfo->sampleRate != prevSampleRate || - mStreamInfo->numChannels != prevNumChannels) { - ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", - prevSampleRate, mStreamInfo->sampleRate, - prevNumChannels, mStreamInfo->numChannels); - - notify(OMX_EventPortSettingsChanged, 1, 0, NULL); - mOutputPortSettingsChange = AWAITING_DISABLED; - - if (inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - } - return; + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; } - } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { - ALOGW("Invalid AAC stream"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } - if (inHeader && inHeader->nFilledLen == 0) { - inInfo->mOwnedByUs = false; - mInputBufferCount++; - inQueue.erase(inQueue.begin()); - mLastInHeader = NULL; - inInfo = NULL; - notifyEmptyBufferDone(inHeader); - inHeader = NULL; - } else { - ALOGV("inHeader->nFilledLen = %d", inHeader ? inHeader->nFilledLen : 0); - } - } while (decoderErr == AAC_DEC_OK); + } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { + ALOGW("Invalid AAC stream"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + return; + } + if (inHeader->nFilledLen == 0) { + inInfo->mOwnedByUs = false; + mInputBufferCount++; + inQueue.erase(inQueue.begin()); + mLastInHeader = NULL; + inInfo = NULL; + notifyEmptyBufferDone(inHeader); + inHeader = NULL; + } else { + ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen); + } } int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels; @@ -817,9 +809,8 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { INT_PCM *outBuffer = reinterpret_cast(outHeader->pBuffer + outHeader->nOffset); - int samplesize = mStreamInfo->numChannels * sizeof(int16_t); if (outHeader->nOffset - + mStreamInfo->frameSize * samplesize + + mStreamInfo->frameSize * mStreamInfo->numChannels * sizeof(int16_t) > outHeader->nAllocLen) { ALOGE("buffer overflow"); mSignalledError = true; @@ -827,67 +818,17 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { return; } - - int available = outputDelayRingBufferSamplesAvailable(); - int numSamples = outHeader->nAllocLen / samplesize; - if (numSamples > available) { - numSamples = available; - } - int64_t currentTime = 0; - if (available) { - - int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels); - numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels); - - ALOGV("%d samples available (%d), or %d frames", - numSamples, available, numFrames); - int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0); - currentTime = *nextTimeStamp; - int32_t *currentBufLeft = &mBufferSizes.editItemAt(0); - for (int i = 0; i < numFrames; i++) { - int32_t decodedSize = mDecodedSizes.itemAt(0); - mDecodedSizes.removeAt(0); - ALOGV("decoded %d of %d", decodedSize, *currentBufLeft); - if (*currentBufLeft > decodedSize) { - // adjust/interpolate next time stamp - *currentBufLeft -= decodedSize; - *nextTimeStamp += mStreamInfo->aacSamplesPerFrame * - 1000000ll / mStreamInfo->sampleRate; - ALOGV("adjusted nextTimeStamp/size to %lld/%d", - *nextTimeStamp, *currentBufLeft); - } else { - // move to next timestamp in list - if (mBufferTimestamps.size() > 0) { - mBufferTimestamps.removeAt(0); - nextTimeStamp = &mBufferTimestamps.editItemAt(0); - mBufferSizes.removeAt(0); - currentBufLeft = &mBufferSizes.editItemAt(0); - ALOGV("moved to next time/size: %lld/%d", - *nextTimeStamp, *currentBufLeft); - } - // try to limit output buffer size to match input buffers - // (e.g when an input buffer contained 4 "sub" frames, output - // at most 4 decoded units in the corresponding output buffer) - // This is optional. Remove the next three lines to fill the output - // buffer with as many units as available. - numFrames = i + 1; - numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels; - break; - } - } - - ALOGV("getting %d from ringbuffer", numSamples); - int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples); - if (ns != numSamples) { - ALOGE("not a complete frame of samples available"); - mSignalledError = true; - notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); - return; - } + int32_t ns = outputDelayRingBufferGetSamples(outBuffer, + mStreamInfo->frameSize * mStreamInfo->numChannels); // TODO: check for overflow + if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) { + ALOGE("not a complete frame of samples available"); + mSignalledError = true; + notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); + return; } - outHeader->nFilledLen = numSamples * sizeof(int16_t); - + outHeader->nFilledLen = mStreamInfo->frameSize * mStreamInfo->numChannels + * sizeof(int16_t); if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) { outHeader->nFlags = OMX_BUFFERFLAG_EOS; mEndOfOutput = true; @@ -895,13 +836,13 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFlags = 0; } - outHeader->nTimeStamp = currentTime; + outHeader->nTimeStamp = mAnchorTimes.isEmpty() ? 0 : mAnchorTimes.itemAt(0); + mAnchorTimes.removeAt(0); mOutputBufferCount++; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; - ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen); notifyFillBufferDone(outHeader); outHeader = NULL; } @@ -936,10 +877,8 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) { outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; - outHeader->nTimeStamp = mBufferTimestamps.itemAt(0); - mBufferTimestamps.clear(); - mBufferSizes.clear(); - mDecodedSizes.clear(); + outHeader->nTimeStamp = mAnchorTimes.itemAt(0); + mAnchorTimes.removeAt(0); mOutputBufferCount++; outInfo->mOwnedByUs = false; @@ -960,9 +899,7 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. // drain all existing data drainDecoder(); - mBufferTimestamps.clear(); - mBufferSizes.clear(); - mDecodedSizes.clear(); + mAnchorTimes.clear(); mLastInHeader = NULL; } else { while (outputDelayRingBufferSamplesAvailable() > 0) { @@ -1018,9 +955,7 @@ void SoftAAC2::onReset() { mOutputDelayRingBufferReadPos = 0; mEndOfInput = false; mEndOfOutput = false; - mBufferTimestamps.clear(); - mBufferSizes.clear(); - mDecodedSizes.clear(); + mAnchorTimes.clear(); mLastInHeader = NULL; // To make the codec behave the same before and after a reset, we need to invalidate the diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h index 9fcb598..865bd15 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.h +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h @@ -59,9 +59,8 @@ private: size_t mOutputBufferCount; bool mSignalledError; OMX_BUFFERHEADERTYPE *mLastInHeader; - Vector mBufferSizes; - Vector mDecodedSizes; - Vector mBufferTimestamps; + int64_t mCurrentInputTime; + Vector mAnchorTimes; CDrcPresModeWrapper mDrcWrap; -- cgit v1.1 From 666c8011c7ea96436b40912d94e6d6097dcfdaf6 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 10 Sep 2014 10:06:11 -0700 Subject: NuPlayerDriver: do not set to paused state when receiving playback complete and reset is in progress. Bug: 17453240 Change-Id: If243e2232779681fc84dc767feaed00f23d8fdb1 --- media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 35cd514..7dd54c1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -626,12 +626,15 @@ void NuPlayerDriver::notifyListener_l( switch (msg) { case MEDIA_PLAYBACK_COMPLETE: { - if (mLooping && mState != STATE_RESET_IN_PROGRESS) { - mPlayer->seekToAsync(0); - break; + if (mState != STATE_RESET_IN_PROGRESS) { + if (mLooping) { + mPlayer->seekToAsync(0); + break; + } + + mPlayer->pause(); + mState = STATE_PAUSED; } - mPlayer->pause(); - mState = STATE_PAUSED; // fall through } -- cgit v1.1 From c640e19c11b3f93e739dd1504159dbe9fe529f0c Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Wed, 10 Sep 2014 13:53:21 -0700 Subject: mediaplayer: release MediaBuffer in stale input buffers Bug: 17454455 Change-Id: If63a6e42f96851d6c10fdec11360f0dabae9bf50 --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 8ce7baf..163a0b5 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -595,7 +595,18 @@ void NuPlayer::Decoder::onMessageReceived(const sp &msg) { { if (!isStaleReply(msg)) { onInputBufferFilled(msg); + } else { + /* release any MediaBuffer passed in the stale buffer */ + sp buffer; + MediaBuffer *mediaBuffer = NULL; + if (msg->findBuffer("buffer", &buffer) && + buffer->meta()->findPointer( + "mediaBuffer", (void **)&mediaBuffer) && + mediaBuffer != NULL) { + mediaBuffer->release(); + } } + break; } -- cgit v1.1 From 332beebb72bd02e8024244f33e0a61f429efaffe Mon Sep 17 00:00:00 2001 From: Jon Eklund Date: Mon, 23 Jun 2014 14:47:03 -0500 Subject: AudioPolicyManager: Use "safe" speaker for notifications if available On particularly loud devices, unexpected audio bursts can be harmful. For longer audio events, the conventional mitigation strategy is to somehow soft-start (ramp) the loudspeaker volume, but this strategy can severely impact the audibility of short audio events. Use of the "safe" speaker path hints to AudioHAL to immediately output at best allowable level for transient audio events. SPEAKER_SAFE is aliased to SPEAKER for purposes of volume control. Bug: 17319721 Change-Id: I75187c23f3d1f18e9f638c5d14e7b0bf805a67bc --- services/audiopolicy/AudioPolicyManager.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 6adcde4..22c4e04 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -64,6 +64,7 @@ struct StringToEnum { const StringToEnum sDeviceNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE), STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE), STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET), STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE), STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO), @@ -3824,6 +3825,14 @@ audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stre break; } } + + /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it + and doesn't really need to.*/ + if (devices & AUDIO_DEVICE_OUT_SPEAKER_SAFE) { + devices |= AUDIO_DEVICE_OUT_SPEAKER; + devices &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE; + } + return devices; } @@ -3926,12 +3935,20 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate // the isStreamActive() method only informs about the activity of a stream, not // if it's for local playback. Note also that we use the same delay between both tests device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); + //user "safe" speaker if available instead of normal speaker to avoid triggering + //other acoustic safety mechanisms for notification + if (device == AUDIO_DEVICE_OUT_SPEAKER && (availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) + device = AUDIO_DEVICE_OUT_SPEAKER_SAFE; } else if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { // while media is playing (or has recently played), use the same device device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/); } else { // when media is not playing anymore, fall back on the sonification behavior device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/); + //user "safe" speaker if available instead of normal speaker to avoid triggering + //other acoustic safety mechanisms for notification + if (device == AUDIO_DEVICE_OUT_SPEAKER && (availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) + device = AUDIO_DEVICE_OUT_SPEAKER_SAFE; } break; @@ -4668,6 +4685,10 @@ audio_devices_t AudioPolicyManager::getDeviceForVolume(audio_devices_t device) } } + /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/ + if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) + device = AUDIO_DEVICE_OUT_SPEAKER; + ALOGW_IF(popcount(device) != 1, "getDeviceForVolume() invalid device combination: %08x", device); -- cgit v1.1 From 715e30cbbc8b1ed62165ef0e33368f27b6865b20 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Mon, 8 Sep 2014 18:55:34 -0700 Subject: StagefrightRecorder: default to codec and fps from camcorder low profile Bug: 16870964 Change-Id: I18425af630d3f041a3bcf77fbae3f07856fe8af2 --- .../libmediaplayerservice/StagefrightRecorder.cpp | 38 ++++++++++++++++++---- media/libmediaplayerservice/StagefrightRecorder.h | 1 + 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index e2bcb1e..b904aa8 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -183,11 +183,7 @@ status_t StagefrightRecorder::setVideoEncoder(video_encoder ve) { return BAD_VALUE; } - if (ve == VIDEO_ENCODER_DEFAULT) { - mVideoEncoder = VIDEO_ENCODER_H263; - } else { - mVideoEncoder = ve; - } + mVideoEncoder = ve; return OK; } @@ -1033,6 +1029,7 @@ status_t StagefrightRecorder::setupRTPRecording() { if (mAudioSource != AUDIO_SOURCE_CNT) { source = createAudioSource(); } else { + setDefaultVideoEncoderIfNecessary(); sp mediaSource; status_t err = setupMediaSource(&mediaSource); @@ -1074,6 +1071,7 @@ status_t StagefrightRecorder::setupMPEG2TSRecording() { if (mVideoSource < VIDEO_SOURCE_LIST_END) { if (mVideoEncoder != VIDEO_ENCODER_H264) { + ALOGE("MPEG2TS recording only supports H.264 encoding!"); return ERROR_UNSUPPORTED; } @@ -1108,6 +1106,12 @@ status_t StagefrightRecorder::setupMPEG2TSRecording() { void StagefrightRecorder::clipVideoFrameRate() { ALOGV("clipVideoFrameRate: encoder %d", mVideoEncoder); + if (mFrameRate == -1) { + mFrameRate = mEncoderProfiles->getCamcorderProfileParamByName( + "vid.fps", mCameraId, CAMCORDER_QUALITY_LOW); + ALOGW("Using default video fps %d", mFrameRate); + } + int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName( "enc.vid.fps.min", mVideoEncoder); int maxFrameRate = mEncoderProfiles->getVideoEncoderParamByName( @@ -1243,6 +1247,27 @@ void StagefrightRecorder::setDefaultProfileIfNecessary() { } } +void StagefrightRecorder::setDefaultVideoEncoderIfNecessary() { + if (mVideoEncoder == VIDEO_ENCODER_DEFAULT) { + if (mOutputFormat == OUTPUT_FORMAT_WEBM) { + // default to VP8 for WEBM recording + mVideoEncoder = VIDEO_ENCODER_VP8; + } else { + // pick the default encoder for CAMCORDER_QUALITY_LOW + int videoCodec = mEncoderProfiles->getCamcorderProfileParamByName( + "vid.codec", mCameraId, CAMCORDER_QUALITY_LOW); + + if (videoCodec > VIDEO_ENCODER_DEFAULT && + videoCodec < VIDEO_ENCODER_LIST_END) { + mVideoEncoder = (video_encoder)videoCodec; + } else { + // default to H.264 if camcorder profile not available + mVideoEncoder = VIDEO_ENCODER_H264; + } + } + } +} + status_t StagefrightRecorder::checkAudioEncoderCapabilities() { clipAudioBitRate(); clipAudioSampleRate(); @@ -1562,6 +1587,7 @@ status_t StagefrightRecorder::setupMPEG4orWEBMRecording() { } if (mVideoSource < VIDEO_SOURCE_LIST_END) { + setDefaultVideoEncoderIfNecessary(); sp mediaSource; err = setupMediaSource(&mediaSource); @@ -1721,7 +1747,7 @@ status_t StagefrightRecorder::reset() { // Default parameters mOutputFormat = OUTPUT_FORMAT_THREE_GPP; mAudioEncoder = AUDIO_ENCODER_AMR_NB; - mVideoEncoder = VIDEO_ENCODER_H263; + mVideoEncoder = VIDEO_ENCODER_DEFAULT; mVideoWidth = 176; mVideoHeight = 144; mFrameRate = -1; diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 9062f30..54c38d3 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -178,6 +178,7 @@ private: void clipAudioSampleRate(); void clipNumberOfAudioChannels(); void setDefaultProfileIfNecessary(); + void setDefaultVideoEncoderIfNecessary(); StagefrightRecorder(const StagefrightRecorder &); -- cgit v1.1 From 5e5a6e100920679f20b4d7fae0d8866ec5053f7e Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 16 Sep 2014 15:43:44 -0700 Subject: Add support for ANDROID_LOOP to NuPlayer Bug: 17518139 Change-Id: I9355ddd4c998d967013dd8bd32d670a9a83dea31 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 10 +++++++--- media/libmediaplayerservice/nuplayer/GenericSource.h | 3 +++ media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 4 ++++ media/libmediaplayerservice/nuplayer/NuPlayer.h | 2 ++ media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 12 +++++++++++- media/libmediaplayerservice/nuplayer/NuPlayerDriver.h | 2 ++ media/libmediaplayerservice/nuplayer/NuPlayerSource.h | 1 + 7 files changed, 30 insertions(+), 4 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index bd67cbd..c6910cb 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -106,6 +106,10 @@ status_t NuPlayer::GenericSource::setDataSource( return OK; } +sp NuPlayer::GenericSource::getFileFormatMeta() const { + return mFileMeta; +} + status_t NuPlayer::GenericSource::initFromDataSource() { sp extractor; @@ -144,10 +148,10 @@ status_t NuPlayer::GenericSource::initFromDataSource() { checkDrmStatus(mDataSource); } - sp fileMeta = extractor->getMetaData(); - if (fileMeta != NULL) { + mFileMeta = extractor->getMetaData(); + if (mFileMeta != NULL) { int64_t duration; - if (fileMeta->findInt64(kKeyDuration, &duration)) { + if (mFileMeta->findInt64(kKeyDuration, &duration)) { mDurationUs = duration; } } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 454edeb..24bb6af 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -59,6 +59,8 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual status_t feedMoreTSData(); + virtual sp getFileFormatMeta() const; + virtual status_t dequeueAccessUnit(bool audio, sp *accessUnit); virtual status_t getDuration(int64_t *durationUs); @@ -125,6 +127,7 @@ private: sp mDataSource; sp mCachedSource; sp mWVMExtractor; + sp mFileMeta; DrmManagerClient *mDrmManagerClient; sp mDecryptHandle; bool mStarted; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 7c6d576..5321deb 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1730,6 +1730,10 @@ status_t NuPlayer::selectTrack(size_t trackIndex, bool select) { return err; } +sp NuPlayer::getFileMeta() { + return mSource->getFileFormatMeta(); +} + void NuPlayer::schedulePollDuration() { sp msg = new AMessage(kWhatPollDuration, id()); msg->setInt32("generation", mPollDurationGeneration); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 2e951bd..7197e5f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -67,6 +67,8 @@ struct NuPlayer : public AHandler { status_t getSelectedTrack(int32_t type, Parcel* reply) const; status_t selectTrack(size_t trackIndex, bool select); + sp getFileMeta(); + static const size_t kAggregateBufferSizeBytes; protected: diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 4e6b4d8..9e2e691 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -45,6 +45,7 @@ NuPlayerDriver::NuPlayerDriver() mPlayerFlags(0), mAtEOS(false), mLooping(false), + mAutoLoop(false), mStartupSeekTimeUs(-1) { mLooper->setName("NuPlayerDriver Looper"); @@ -505,6 +506,7 @@ status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) { void NuPlayerDriver::setAudioSink(const sp &audioSink) { mPlayer->setAudioSink(audioSink); + mAudioSink = audioSink; } status_t NuPlayerDriver::setParameter( @@ -634,7 +636,8 @@ void NuPlayerDriver::notifyListener_l( case MEDIA_PLAYBACK_COMPLETE: { if (mState != STATE_RESET_IN_PROGRESS) { - if (mLooping) { + if (mLooping || (mAutoLoop + && (mAudioSink == NULL || mAudioSink->realtime()))) { mPlayer->seekToAsync(0); break; } @@ -700,6 +703,13 @@ void NuPlayerDriver::notifyPrepareCompleted(status_t err) { } } + sp meta = mPlayer->getFileMeta(); + int32_t loop; + if (meta != NULL + && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { + mAutoLoop = true; + } + mCondition.broadcast(); } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index e81d605..f2bd431 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -114,10 +114,12 @@ private: sp mLooper; sp mPlayer; + sp mAudioSink; uint32_t mPlayerFlags; bool mAtEOS; bool mLooping; + bool mAutoLoop; int64_t mStartupSeekTimeUs; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 7d994fa..2f06c31 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -76,6 +76,7 @@ struct NuPlayer::Source : public AHandler { virtual sp getFormat(bool audio); virtual sp getFormatMeta(bool /* audio */) { return NULL; } + virtual sp getFileFormatMeta() const { return NULL; } virtual status_t dequeueAccessUnit( bool audio, sp *accessUnit) = 0; -- cgit v1.1 From a7326b42c42f5014e8dabf18d69a8376b2f3f67d Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Thu, 18 Sep 2014 14:07:18 -0700 Subject: AudioEffect acquires session Currently, users of audio sessions, AudioTrack and AudioRecord, are acquiring and releasing audio sessions according to their life-cycle. AudioEffect instances were not counting as users of an audio session. This caused an effect used on a session to be purged by AudioFlinger::purgeStaleEffects_l() whenever the last user of that session went away. This CL makes AudioEffect acquire and release a session when created and destroyed. Bug 15432115 Change-Id: I922532150009988d43872f9b5928044a830ae0b3 --- include/media/AudioEffect.h | 1 + media/libmedia/AudioEffect.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h index f98002d..4932d40 100644 --- a/include/media/AudioEffect.h +++ b/include/media/AudioEffect.h @@ -449,6 +449,7 @@ private: sp mIEffectClient; // IEffectClient implementation sp mCblkMemory; // shared memory for deferred parameter setting effect_param_cblk_t* mCblk; // control block for deferred parameter setting + pid_t mClientPid; }; diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index 35f6557..0d5d7e4 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -145,15 +145,19 @@ status_t AudioEffect::set(const effect_uuid_t *type, return mStatus; } - mIEffect = iEffect; mCblkMemory = cblk; mCblk = static_cast(cblk->pointer()); int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int); mCblk->buffer = (uint8_t *)mCblk + bufOffset; iEffect->asBinder()->linkToDeath(mIEffectClient); - ALOGV("set() %p OK effect: %s id: %d status %d enabled %d", this, mDescriptor.name, mId, - mStatus, mEnabled); + mClientPid = IPCThreadState::self()->getCallingPid(); + ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId, + mStatus, mEnabled, mClientPid); + + if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) { + AudioSystem::acquireAudioSessionId(mSessionId, mClientPid); + } return mStatus; } @@ -164,6 +168,9 @@ AudioEffect::~AudioEffect() ALOGV("Destructor %p", this); if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) { + if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) { + AudioSystem::releaseAudioSessionId(mSessionId, mClientPid); + } if (mIEffect != NULL) { mIEffect->disconnect(); mIEffect->asBinder()->unlinkToDeath(mIEffectClient); -- cgit v1.1