Merge "NuPlayer: Fix flush mode decoder error handling" into lmp-dev
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index da4c20c..df0dc58 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -267,7 +267,8 @@
bool encoder,
int32_t numChannels, int32_t sampleRate, int32_t bitRate,
int32_t aacProfile, bool isADTS, int32_t sbrMode,
- int32_t maxOutputChannelCount, const drcParams_t& drc);
+ int32_t maxOutputChannelCount, const drcParams_t& drc,
+ int32_t pcmLimiterEnable);
status_t setupAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate);
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 8000e84..3630263 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -34,6 +34,7 @@
struct AString;
struct IMediaHTTPService;
class String8;
+struct HTTPBase;
class DataSource : public RefBase {
public:
@@ -48,7 +49,10 @@
const sp<IMediaHTTPService> &httpService,
const char *uri,
const KeyedVector<String8, String8> *headers = NULL,
- String8 *contentType = NULL);
+ String8 *contentType = NULL,
+ HTTPBase *httpSource = NULL);
+
+ static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
DataSource() {}
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
index 14b31ec..d3b4a35 100644
--- a/media/img_utils/src/DngUtils.cpp
+++ b/media/img_utils/src/DngUtils.cpp
@@ -229,7 +229,9 @@
err = mEndianOut.write(version, 0, NELEMS(version));
if (err != OK) return err;
- uint32_t flags = FLAG_OPTIONAL | FLAG_OPTIONAL_FOR_PREVIEW;
+ // Do not include optional flag for preview, as this can have a large effect on the output.
+ uint32_t flags = FLAG_OPTIONAL;
+
err = mEndianOut.write(&flags, 0, 1);
if (err != OK) return err;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index baf211b..6859a1a 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -36,6 +36,7 @@
#include "../../libstagefright/include/DRMExtractor.h"
#include "../../libstagefright/include/NuCachedSource2.h"
#include "../../libstagefright/include/WVMExtractor.h"
+#include "../../libstagefright/include/HTTPBase.h"
namespace android {
@@ -64,6 +65,7 @@
mAudioTimeUs = 0;
mVideoTimeUs = 0;
mHTTPService.clear();
+ mHttpSource.clear();
mUri.clear();
mUriHeaders.clear();
mFd = -1;
@@ -285,10 +287,23 @@
// delayed data source creation
if (mDataSource == NULL) {
if (!mUri.empty()) {
- mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
+ const char* uri = mUri.c_str();
+ mIsWidevine = !strncasecmp(uri, "widevine://", 11);
+
+ if (!strncasecmp("http://", uri, 7)
+ || !strncasecmp("https://", uri, 8)
+ || mIsWidevine) {
+ mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
+ if (mHttpSource == NULL) {
+ ALOGE("Failed to create http source!");
+ notifyPreparedAndCleanup(UNKNOWN_ERROR);
+ return;
+ }
+ }
mDataSource = DataSource::CreateFromURI(
- mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType);
+ mHTTPService, uri, &mUriHeaders, &mContentType,
+ static_cast<HTTPBase *>(mHttpSource.get()));
} else {
// set to false first, if the extractor
// comes back as secure, set it to true then.
@@ -361,6 +376,7 @@
mSniffedMIME = "";
mDataSource.clear();
mCachedSource.clear();
+ mHttpSource.clear();
cancelPollBuffering();
}
@@ -487,6 +503,8 @@
if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
}
+ } else if (mHttpSource != NULL) {
+ static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
}
}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 1741f27..f8601ea 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -127,6 +127,7 @@
sp<DataSource> mDataSource;
sp<NuCachedSource2> mCachedSource;
+ sp<DataSource> mHttpSource;
sp<WVMExtractor> mWVMExtractor;
sp<MetaData> mFileMeta;
DrmManagerClient *mDrmManagerClient;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 8313da6..7e5087f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -20,6 +20,8 @@
#include "NuPlayerRenderer.h"
+#include <cutils/properties.h>
+
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -39,6 +41,16 @@
// static
const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
+static bool sFrameAccurateAVsync = false;
+
+static void readProperties() {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("persist.sys.media.avsync", value, NULL)) {
+ sFrameAccurateAVsync =
+ !strcmp("1", value) || !strcasecmp("true", value);
+ }
+}
+
NuPlayer::Renderer::Renderer(
const sp<MediaPlayerBase::AudioSink> &sink,
const sp<AMessage> ¬ify,
@@ -68,6 +80,7 @@
mVideoLateByUs(0ll),
mAudioOffloadPauseTimeoutGeneration(0),
mAudioOffloadTornDown(false) {
+ readProperties();
}
NuPlayer::Renderer::~Renderer() {
@@ -576,6 +589,11 @@
ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);
// post 2 display refreshes before rendering is due
+ // FIXME currently this increases power consumption, so unless frame-accurate
+ // AV sync is requested, post closer to required render time (at 0.63 vsyncs)
+ if (!sFrameAccurateAVsync) {
+ twoVsyncsUs >>= 4;
+ }
msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
mDrainVideoQueuePending = true;
@@ -976,6 +994,8 @@
}
void NuPlayer::Renderer::onResume() {
+ readProperties();
+
if (!mPaused) {
return;
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 4589ed1..d6fba98 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1359,6 +1359,7 @@
int32_t isADTS, aacProfile;
int32_t sbrMode;
int32_t maxOutputChannelCount;
+ int32_t pcmLimiterEnable;
drcParams_t drc;
if (!msg->findInt32("is-adts", &isADTS)) {
isADTS = 0;
@@ -1373,6 +1374,10 @@
if (!msg->findInt32("aac-max-output-channel_count", &maxOutputChannelCount)) {
maxOutputChannelCount = -1;
}
+ if (!msg->findInt32("aac-pcm-limiter-enable", &pcmLimiterEnable)) {
+ // value is unknown
+ pcmLimiterEnable = -1;
+ }
if (!msg->findInt32("aac-encoded-target-level", &drc.encodedTargetLevel)) {
// value is unknown
drc.encodedTargetLevel = -1;
@@ -1396,7 +1401,8 @@
err = setupAACCodec(
encoder, numChannels, sampleRate, bitRate, aacProfile,
- isADTS != 0, sbrMode, maxOutputChannelCount, drc);
+ isADTS != 0, sbrMode, maxOutputChannelCount, drc,
+ pcmLimiterEnable);
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
err = setupAMRCodec(encoder, false /* isWAMR */, bitRate);
@@ -1561,7 +1567,8 @@
status_t ACodec::setupAACCodec(
bool encoder, int32_t numChannels, int32_t sampleRate,
int32_t bitRate, int32_t aacProfile, bool isADTS, int32_t sbrMode,
- int32_t maxOutputChannelCount, const drcParams_t& drc) {
+ int32_t maxOutputChannelCount, const drcParams_t& drc,
+ int32_t pcmLimiterEnable) {
if (encoder && isADTS) {
return -EINVAL;
}
@@ -1691,6 +1698,7 @@
presentation.nHeavyCompression = drc.heavyCompression;
presentation.nTargetReferenceLevel = drc.targetRefLevel;
presentation.nEncodedTargetLevel = drc.encodedTargetLevel;
+ presentation.nPCMLimiterEnable = pcmLimiterEnable;
status_t res = mOMX->setParameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
if (res == OK) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index a72cbd5..c99db84 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -186,7 +186,8 @@
const sp<IMediaHTTPService> &httpService,
const char *uri,
const KeyedVector<String8, String8> *headers,
- String8 *contentType) {
+ String8 *contentType,
+ HTTPBase *httpSource) {
if (contentType != NULL) {
*contentType = "";
}
@@ -204,14 +205,15 @@
return NULL;
}
- sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
- if (conn == NULL) {
- ALOGE("Failed to make http connection from http service!");
- return NULL;
+ if (httpSource == NULL) {
+ sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+ if (conn == NULL) {
+ ALOGE("Failed to make http connection from http service!");
+ return NULL;
+ }
+ httpSource = new MediaHTTP(conn);
}
- sp<HTTPBase> httpSource = new MediaHTTP(conn);
-
String8 tmp;
if (isWidevine) {
tmp = String8("http://");
@@ -264,6 +266,19 @@
return source;
}
+sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
+ if (httpService == NULL) {
+ return NULL;
+ }
+
+ sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+ if (conn == NULL) {
+ return NULL;
+ } else {
+ return new MediaHTTP(conn);
+ }
+}
+
String8 DataSource::getMIMEType() const {
return String8("application/octet-stream");
}
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index f469d4d..bd0a41d 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -456,6 +456,10 @@
}
Mutex::Autolock autoLock(mLock);
+ if (mDisconnecting) {
+ mCondition.signal();
+ return;
+ }
CHECK(mAsyncResult == NULL);
@@ -502,6 +506,9 @@
ALOGV("readAt offset %lld, size %zu", offset, size);
Mutex::Autolock autoLock(mLock);
+ if (mDisconnecting) {
+ return ERROR_END_OF_STREAM;
+ }
// If the request can be completely satisfied from the cache, do so.
@@ -528,6 +535,7 @@
}
if (mDisconnecting) {
+ mAsyncResult.clear();
return ERROR_END_OF_STREAM;
}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index e701e9e..1b6eac4 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -368,6 +368,10 @@
aacPresParams->nEncodedTargetLevel);
updateDrcWrapper = true;
}
+ if (aacPresParams->nPCMLimiterEnable >= 0) {
+ aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE,
+ (aacPresParams->nPCMLimiterEnable != 0));
+ }
if (updateDrcWrapper) {
mDrcWrap.update();
}
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 7a9a1a3..fba6b09 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -494,6 +494,10 @@
AString uri;
CHECK(msg->findString("uri", &uri));
+ if (mFetcherInfos.indexOfKey(uri) < 0) {
+ ALOGE("couldn't find uri");
+ break;
+ }
FetcherInfo *info = &mFetcherInfos.editValueFor(uri);
info->mIsPrepared = true;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 15f1f23..4678880 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -465,16 +465,21 @@
if (status == 0) {
status = cmdStatus;
}
- if (status == 0 &&
- ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
- (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) {
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- audio_stream_t *stream = thread->stream();
- if (stream != NULL) {
- stream->add_audio_effect(stream, mEffectInterface);
+ if (status == 0) {
+ if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+ (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ audio_stream_t *stream = thread->stream();
+ if (stream != NULL) {
+ stream->add_audio_effect(stream, mEffectInterface);
+ }
}
}
+ sp<EffectChain> chain = mChain.promote();
+ if (chain != 0) {
+ chain->forceVolume();
+ }
}
return status;
}
@@ -1326,7 +1331,7 @@
int sessionId)
: mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
- mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
+ mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX), mForceVolume(false)
{
mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
if (thread == NULL) {
@@ -1649,7 +1654,8 @@
}
}
- if (ctrlIdx == mVolumeCtrlIdx && *left == mLeftVolume && *right == mRightVolume) {
+ if (!isVolumeForced() && ctrlIdx == mVolumeCtrlIdx &&
+ *left == mLeftVolume && *right == mRightVolume) {
if (hasControl) {
*left = mNewLeftVolume;
*right = mNewRightVolume;
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index eaf90e7..b87a1fd 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -318,6 +318,12 @@
// At least one non offloadable effect in the chain is enabled
bool isNonOffloadableEnabled();
+ // use release_cas because we don't care about the observed value, just want to make sure the
+ // new value is observable.
+ void forceVolume() { android_atomic_release_cas(false, true, &mForceVolume); }
+ // use acquire_cas because we are interested in the observed value and
+ // we are the only observers.
+ bool isVolumeForced() { return (android_atomic_acquire_cas(true, false, &mForceVolume) == 0); }
void dump(int fd, const Vector<String16>& args);
@@ -375,4 +381,5 @@
// timeLow fields among effect type UUIDs.
// Updated by updateSuspendedSessions_l() only.
KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
+ volatile int32_t mForceVolume; // force next volume command because a new effect was enabled
};
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 66edf45..12e09ab 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2126,7 +2126,6 @@
size_t totalFramesWritten = mNormalSink->framesWritten();
if (totalFramesWritten >= mLatchD.mTimestamp.mPosition) {
mLatchD.mUnpresentedFrames = totalFramesWritten - mLatchD.mTimestamp.mPosition;
- // mLatchD.mFramesReleased is set in threadloop_mix()
mLatchDValid = true;
}
}
@@ -3094,18 +3093,6 @@
sleepTime = 0;
standbyTime = systemTime() + standbyDelay;
//TODO: delay standby when effects have a tail
-
- mLatchD.mFramesReleased.clear();
- {
- Mutex::Autolock _l(mLock);
- size_t size = mActiveTracks.size();
- for (size_t i = 0; i < size; i++) {
- sp<Track> t = mActiveTracks[i].promote();
- if (t != 0) {
- mLatchD.mFramesReleased.add(t.get(), t->mAudioTrackServerProxy->framesReleased());
- }
- }
- }
}
void AudioFlinger::MixerThread::threadLoop_sleepTime()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 7d3b854..7af5264 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -819,7 +819,6 @@
struct {
AudioTimestamp mTimestamp;
uint32_t mUnpresentedFrames;
- KeyedVector<Track *, uint32_t> mFramesReleased;
} mLatchD, mLatchQ;
bool mLatchDValid; // true means mLatchD is valid, and clock it into latch at next opportunity
bool mLatchQValid; // true means mLatchQ is valid
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b2d53cf..75190f3 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -898,15 +898,7 @@
uint32_t unpresentedFrames =
((int64_t) playbackThread->mLatchQ.mUnpresentedFrames * mSampleRate) /
playbackThread->mSampleRate;
- // FIXME Since we're using a raw pointer as the key, it is theoretically possible
- // for a brand new track to share the same address as a recently destroyed
- // track, and thus for us to get the frames released of the wrong track.
- // It is unlikely that we would be able to call getTimestamp() so quickly
- // right after creating a new track. Nevertheless, the index here should
- // be changed to something that is unique. Or use a completely different strategy.
- ssize_t i = playbackThread->mLatchQ.mFramesReleased.indexOfKey(this);
- uint32_t framesWritten = i >= 0 ?
- playbackThread->mLatchQ.mFramesReleased[i] : mAudioTrackServerProxy->framesReleased();
+ uint32_t framesWritten = mAudioTrackServerProxy->framesReleased();
bool checkPreviousTimestamp = mPreviousValid && framesWritten >= mPreviousFramesWritten;
if (framesWritten < unpresentedFrames) {
mPreviousValid = false;