diff options
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp | 19 | ||||
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h | 1 | ||||
-rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 4 | ||||
-rw-r--r-- | media/libstagefright/DataSource.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/MediaCodec.cpp | 7 | ||||
-rw-r--r-- | media/libstagefright/NuCachedSource2.cpp | 15 | ||||
-rw-r--r-- | media/libstagefright/OggExtractor.cpp | 102 | ||||
-rw-r--r-- | media/libstagefright/foundation/base64.cpp | 11 | ||||
-rw-r--r-- | media/libstagefright/include/NuCachedSource2.h | 7 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 6 | ||||
-rw-r--r-- | services/audioflinger/Tracks.cpp | 5 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.cpp | 2 | ||||
-rw-r--r-- | services/camera/libcameraservice/device3/Camera3Stream.cpp | 5 | ||||
-rw-r--r-- | services/mediaresourcemanager/ResourceManagerService.cpp | 9 |
14 files changed, 89 insertions, 106 deletions
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 0ac29a8..bca2888 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -106,6 +106,7 @@ NuPlayer::Renderer::Renderer( mNotifyCompleteVideo(false), mSyncQueues(false), mPaused(false), + mPauseDrainAudioAllowedUs(0), mVideoSampleReceived(false), mVideoRenderingStarted(false), mVideoRenderingStartGeneration(0), @@ -630,6 +631,14 @@ void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) { return; } + // FIXME: if paused, wait until AudioTrack stop() is complete before delivering data. + if (mPaused) { + const int64_t diffUs = mPauseDrainAudioAllowedUs - ALooper::GetNowUs(); + if (diffUs > delayUs) { + delayUs = diffUs; + } + } + mDrainAudioQueuePending = true; sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this); msg->setInt32("drainGeneration", mAudioDrainGeneration); @@ -1344,8 +1353,16 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) { mAudioSink->flush(); // Call stop() to signal to the AudioSink to completely fill the // internal buffer before resuming playback. + // FIXME: this is ignored after flush(). mAudioSink->stop(); - if (!mPaused) { + if (mPaused) { + // Race condition: if renderer is paused and audio sink is stopped, + // we need to make sure that the audio track buffer fully drains + // before delivering data. + // FIXME: remove this if we can detect if stop() is complete. + const int delayUs = 2 * 50 * 1000; // (2 full mixer thread cycles at 50ms) + mPauseDrainAudioAllowedUs = ALooper::GetNowUs() + delayUs; + } else { mAudioSink->start(); } mNumFramesWritten = 0; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 3e65649..87bcbf9 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -170,6 +170,7 @@ private: // modified on only renderer's thread. bool mPaused; + int64_t mPauseDrainAudioAllowedUs; // time when we can drain/deliver audio in pause mode. bool mVideoSampleReceived; bool mVideoRenderingStarted; diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 4e6c2a6..3cd0b0e 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -2290,11 +2290,11 @@ status_t AwesomePlayer::finishSetDataSource_l() { // The widevine extractor does its own caching. #if 0 - mCachedSource = new NuCachedSource2( + mCachedSource = NuCachedSource2::Create( new ThrottledSource( mConnectingDataSource, 50 * 1024 /* bytes/sec */)); #else - mCachedSource = new NuCachedSource2( + mCachedSource = NuCachedSource2::Create( mConnectingDataSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 75ef288..5020c6c 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -246,7 +246,7 @@ sp<DataSource> DataSource::CreateFromURI( *contentType = httpSource->getMIMEType(); } - source = new NuCachedSource2( + source = NuCachedSource2::Create( httpSource, cacheConfig.isEmpty() ? NULL : cacheConfig.string(), disconnectAtHighwatermark); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index cd59709..7019537 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -572,6 +572,7 @@ status_t MediaCodec::stop() { } status_t MediaCodec::reclaim() { + ALOGD("MediaCodec::reclaim(%p) %s", this, mInitName.c_str()); sp<AMessage> msg = new AMessage(kWhatRelease, this); msg->setInt32("reclaimed", 1); @@ -1154,8 +1155,10 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { resourceType = String8(kResourceNonSecureCodec); } - const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec; - addResource(resourceType, String8(subtype), 1); + if (mIsVideo) { + // audio codec is currently ignored. + addResource(resourceType, String8(kResourceVideoCodec), 1); + } (new AMessage)->postReply(mReplyID); break; diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index f82636b..d6255d6 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -224,9 +224,6 @@ NuCachedSource2::NuCachedSource2( // So whenever we call DataSource::readAt it may end up in a call to // IMediaHTTPConnection::readAt and therefore call back into JAVA. mLooper->start(false /* runOnCallingThread */, true /* canCallJava */); - - Mutex::Autolock autoLock(mLock); - (new AMessage(kWhatFetchMore, mReflector))->post(); } NuCachedSource2::~NuCachedSource2() { @@ -237,6 +234,18 @@ NuCachedSource2::~NuCachedSource2() { mCache = NULL; } +// static +sp<NuCachedSource2> NuCachedSource2::Create( + const sp<DataSource> &source, + const char *cacheConfig, + bool disconnectAtHighwatermark) { + sp<NuCachedSource2> instance = new NuCachedSource2( + source, cacheConfig, disconnectAtHighwatermark); + Mutex::Autolock autoLock(instance->mLock); + (new AMessage(kWhatFetchMore, instance->mReflector))->post(); + return instance; +} + status_t NuCachedSource2::getEstimatedBandwidthKbps(int32_t *kbps) { if (mSource->flags() & kIsHTTPBasedSource) { HTTPBase* source = static_cast<HTTPBase *>(mSource.get()); diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index d5c929e..578171f 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -23,6 +23,7 @@ #include <cutils/properties.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/base64.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaBufferGroup.h> @@ -1202,93 +1203,18 @@ void parseVorbisComment( } -// The returned buffer should be free()d. -static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) { - *outSize = 0; - - if ((size % 4) != 0) { - return NULL; - } - - size_t n = size; - size_t padding = 0; - if (n >= 1 && s[n - 1] == '=') { - padding = 1; - - if (n >= 2 && s[n - 2] == '=') { - padding = 2; - } - } - - // We divide first to avoid overflow. It's OK to do this because we - // already made sure that size % 4 == 0. - size_t outLen = (size / 4) * 3 - padding; - - void *buffer = malloc(outLen); - if (buffer == NULL) { - return NULL; - } - - uint8_t *out = (uint8_t *)buffer; - size_t j = 0; - uint32_t accum = 0; - for (size_t i = 0; i < n; ++i) { - char c = s[i]; - unsigned value; - if (c >= 'A' && c <= 'Z') { - value = c - 'A'; - } else if (c >= 'a' && c <= 'z') { - value = 26 + c - 'a'; - } else if (c >= '0' && c <= '9') { - value = 52 + c - '0'; - } else if (c == '+') { - value = 62; - } else if (c == '/') { - value = 63; - } else if (c != '=') { - break; - } else { - if (i < n - padding) { - break; - } - - value = 0; - } - - accum = (accum << 6) | value; - - if (((i + 1) % 4) == 0) { - out[j++] = (accum >> 16); - - if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } - if (j < outLen) { out[j++] = accum & 0xff; } - - accum = 0; - } - } - - // Check if we exited the loop early. - if (j < outLen) { - free(buffer); - return NULL; - } - - *outSize = outLen; - return (uint8_t *)buffer; -} - static void extractAlbumArt( const sp<MetaData> &fileMeta, const void *data, size_t size) { ALOGV("extractAlbumArt from '%s'", (const char *)data); - size_t flacSize; - uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize); - - if (flac == NULL) { + sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size)); + if (flacBuffer == NULL) { ALOGE("malformed base64 encoded data."); return; } + size_t flacSize = flacBuffer->size(); + uint8_t *flac = flacBuffer->data(); ALOGV("got flac of size %zu", flacSize); uint32_t picType; @@ -1298,24 +1224,24 @@ static void extractAlbumArt( char type[128]; if (flacSize < 8) { - goto exit; + return; } picType = U32_AT(flac); if (picType != 3) { // This is not a front cover. - goto exit; + return; } typeLen = U32_AT(&flac[4]); if (typeLen > sizeof(type) - 1) { - goto exit; + return; } // we've already checked above that flacSize >= 8 if (flacSize - 8 < typeLen) { - goto exit; + return; } memcpy(type, &flac[8], typeLen); @@ -1325,7 +1251,7 @@ static void extractAlbumArt( if (!strcmp(type, "-->")) { // This is not inline cover art, but an external url instead. - goto exit; + return; } descLen = U32_AT(&flac[8 + typeLen]); @@ -1333,7 +1259,7 @@ static void extractAlbumArt( if (flacSize < 32 || flacSize - 32 < typeLen || flacSize - 32 - typeLen < descLen) { - goto exit; + return; } dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]); @@ -1341,7 +1267,7 @@ static void extractAlbumArt( // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0 if (flacSize - 32 - typeLen - descLen < dataLen) { - goto exit; + return; } ALOGV("got image data, %zu trailing bytes", @@ -1351,10 +1277,6 @@ static void extractAlbumArt( kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen); fileMeta->setCString(kKeyAlbumArtMIME, type); - -exit: - free(flac); - flac = NULL; } //////////////////////////////////////////////////////////////////////////////// diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp index dcf5bef..7da7db9 100644 --- a/media/libstagefright/foundation/base64.cpp +++ b/media/libstagefright/foundation/base64.cpp @@ -22,11 +22,11 @@ namespace android { sp<ABuffer> decodeBase64(const AString &s) { - if ((s.size() % 4) != 0) { + size_t n = s.size(); + if ((n % 4) != 0) { return NULL; } - size_t n = s.size(); size_t padding = 0; if (n >= 1 && s.c_str()[n - 1] == '=') { padding = 1; @@ -40,11 +40,16 @@ sp<ABuffer> decodeBase64(const AString &s) { } } - size_t outLen = 3 * s.size() / 4 - padding; + // We divide first to avoid overflow. It's OK to do this because we + // already made sure that n % 4 == 0. + size_t outLen = (n / 4) * 3 - padding; sp<ABuffer> buffer = new ABuffer(outLen); uint8_t *out = buffer->data(); + if (out == NULL || buffer->size() < outLen) { + return NULL; + } size_t j = 0; uint32_t accum = 0; for (size_t i = 0; i < n; ++i) { diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index 4252706..a29bdf9 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -28,7 +28,7 @@ struct ALooper; struct PageCache; struct NuCachedSource2 : public DataSource { - NuCachedSource2( + static sp<NuCachedSource2> Create( const sp<DataSource> &source, const char *cacheConfig = NULL, bool disconnectAtHighwatermark = false); @@ -72,6 +72,11 @@ protected: private: friend struct AHandlerReflector<NuCachedSource2>; + NuCachedSource2( + const sp<DataSource> &source, + const char *cacheConfig, + bool disconnectAtHighwatermark); + enum { kPageSize = 65536, kDefaultHighWaterThreshold = 20 * 1024 * 1024, diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 0a7d4a2..5bd9149 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -3479,6 +3479,12 @@ ssize_t AudioFlinger::MixerThread::threadLoop_write() if (state->mCommand != FastMixerState::MIX_WRITE && (kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)) { if (state->mCommand == FastMixerState::COLD_IDLE) { + + // FIXME workaround for first HAL write being CPU bound on some devices + ATRACE_BEGIN("write"); + mOutput->write((char *)mSinkBuffer, 0); + ATRACE_END(); + int32_t old = android_atomic_inc(&mFastMixerFutex); if (old == -1) { (void) syscall(__NR_futex, &mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1); diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index f7da209..b3fac0b 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -432,7 +432,10 @@ AudioFlinger::PlaybackThread::Track::Track( } // only allocate a fast track index if we were able to allocate a normal track name if (flags & IAudioFlinger::TRACK_FAST) { - mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads(); + // FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential + // race with setSyncEvent(). However, if we call it, we cannot properly start + // static fast tracks (SoundPool) immediately after stopping. + //mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads(); ALOG_ASSERT(thread->mFastTrackAvailMask != 0); int i = __builtin_ctz(thread->mFastTrackAvailMask); ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks); diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 7e33e0c..2aaefe9 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -2265,7 +2265,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { String8 result("Dump of the Camera Service:\n"); if (checkCallingPermission(String16("android.permission.DUMP")) == false) { - result.appendFormat("Permission Denial: " + result = result.format("Permission Denial: " "can't dump CameraService from pid=%d, uid=%d\n", getCallingPid(), getCallingUid()); diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 691764f..96299b3 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -487,9 +487,12 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, status_t res = returnBufferLocked(buffer, timestamp); if (res == OK) { fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true); - mOutputBufferReturnedSignal.signal(); } + // Even if returning the buffer failed, we still want to signal whoever is waiting for the + // buffer to be returned. + mOutputBufferReturnedSignal.signal(); + return res; } diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp index e54cc5a..4790754 100644 --- a/services/mediaresourcemanager/ResourceManagerService.cpp +++ b/services/mediaresourcemanager/ResourceManagerService.cpp @@ -96,6 +96,15 @@ status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */ const size_t SIZE = 256; char buffer[SIZE]; + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { + result.format("Permission Denial: " + "can't dump ResourceManagerService from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + write(fd, result.string(), result.size()); + return PERMISSION_DENIED; + } + snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this); result.append(buffer); result.append(" Policies:\n"); |