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