summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/MediaCodecSource.cpp
diff options
context:
space:
mode:
authorChong Zhang <chz@google.com>2014-08-01 10:30:26 -0700
committerChong Zhang <chz@google.com>2014-08-04 11:59:05 -0700
commit16e79115e497386eaf010af388627f94314a55a3 (patch)
tree600138fd3483f527278304fbf866be53f40e6ea1 /media/libstagefright/MediaCodecSource.cpp
parent44622db93a24219123facbbe14259000f90de728 (diff)
downloadframeworks_av-16e79115e497386eaf010af388627f94314a55a3.zip
frameworks_av-16e79115e497386eaf010af388627f94314a55a3.tar.gz
frameworks_av-16e79115e497386eaf010af388627f94314a55a3.tar.bz2
MediaCodecSource: stop puller from caller's thread instead of looper
Currently CameraSource/AudioSource's stop() and read() are both called from the puller's looper. This works if source operates normally (i.e. read() returns regularly before source is stopped), as the stop() will eventually be handled by the looper. However, if for some reason the source hang, it will get stuck in read(), and the stop() will never be processed, which could lead to ANR (in addition to the source hang). We need to move the source's stop out of the puller's looper. It also can't be on MediaCodecSource's looper, because the source's stop synchrounously waits for all outstanding buffers to return, these are only returned when MediaCodecSource's looper processes the buffer. This change moves the stop to MediaCodecSource::stop, after encoder is shutdown. Bug: 16522726 Change-Id: Ie91f563c5d8a98ab091bf1945af4e51f662b9403
Diffstat (limited to 'media/libstagefright/MediaCodecSource.cpp')
-rw-r--r--media/libstagefright/MediaCodecSource.cpp74
1 files changed, 42 insertions, 32 deletions
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 9868ecf..1a80dcc 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -54,7 +54,7 @@ struct MediaCodecSource::Puller : public AHandler {
Puller(const sp<MediaSource> &source);
status_t start(const sp<MetaData> &meta, const sp<AMessage> &notify);
- void stopAsync();
+ void stop();
void pause();
void resume();
@@ -139,8 +139,17 @@ status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta,
return postSynchronouslyAndReturnError(msg);
}
-void MediaCodecSource::Puller::stopAsync() {
- ALOGV("puller (%s) stopAsync", mIsAudio ? "audio" : "video");
+void MediaCodecSource::Puller::stop() {
+ // Stop source from caller's thread instead of puller's looper.
+ // mSource->stop() is thread-safe, doing it outside the puller's
+ // looper allows us to at least stop if source gets stuck.
+ // If source gets stuck in read(), the looper would never
+ // be able to process the stop(), which could lead to ANR.
+
+ ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video");
+ mSource->stop();
+ ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
+
(new AMessage(kWhatStop, id()))->post();
}
@@ -194,9 +203,6 @@ void MediaCodecSource::Puller::onMessageReceived(const sp<AMessage> &msg) {
case kWhatStop:
{
- ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video");
- mSource->stop();
- ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
++mPullGeneration;
handleEOS();
@@ -283,7 +289,21 @@ status_t MediaCodecSource::start(MetaData* params) {
status_t MediaCodecSource::stop() {
sp<AMessage> msg = new AMessage(kWhatStop, mReflector->id());
- return postSynchronouslyAndReturnError(msg);
+ status_t err = postSynchronouslyAndReturnError(msg);
+
+ // mPuller->stop() needs to be done outside MediaCodecSource's looper,
+ // as it contains a synchronous call to stop the underlying MediaSource,
+ // which often waits for all outstanding MediaBuffers to return, but
+ // MediaBuffers are only returned when MediaCodecSource looper gets
+ // to process them.
+
+ if (mPuller != NULL) {
+ ALOGI("puller (%s) stopping", mIsVideo ? "video" : "audio");
+ mPuller->stop();
+ ALOGI("puller (%s) stopped", mIsVideo ? "video" : "audio");
+ }
+
+ return err;
}
status_t MediaCodecSource::pause() {
@@ -301,10 +321,10 @@ status_t MediaCodecSource::read(
Mutex::Autolock autolock(mOutputBufferLock);
*buffer = NULL;
- while (mOutputBufferQueue.size() == 0 && !mEncodedReachedEOS) {
+ while (mOutputBufferQueue.size() == 0 && !mEncoderReachedEOS) {
mOutputBufferCond.wait(mOutputBufferLock);
}
- if (!mEncodedReachedEOS) {
+ if (!mEncoderReachedEOS) {
*buffer = *mOutputBufferQueue.begin();
mOutputBufferQueue.erase(mOutputBufferQueue.begin());
return OK;
@@ -330,9 +350,8 @@ MediaCodecSource::MediaCodecSource(
mStarted(false),
mStopping(false),
mDoMoreWorkPending(false),
- mPullerReachedEOS(false),
mFirstSampleTimeUs(-1ll),
- mEncodedReachedEOS(false),
+ mEncoderReachedEOS(false),
mErrorCode(OK) {
CHECK(mLooper != NULL);
@@ -434,7 +453,7 @@ status_t MediaCodecSource::initEncoder() {
return err;
}
- mEncodedReachedEOS = false;
+ mEncoderReachedEOS = false;
mErrorCode = OK;
return OK;
@@ -465,10 +484,6 @@ void MediaCodecSource::releaseEncoder() {
mEncoderOutputBuffers.clear();
}
-bool MediaCodecSource::reachedEOS() {
- return mEncodedReachedEOS && ((mPuller == NULL) || mPullerReachedEOS);
-}
-
status_t MediaCodecSource::postSynchronouslyAndReturnError(
const sp<AMessage> &msg) {
sp<AMessage> response;
@@ -486,8 +501,8 @@ status_t MediaCodecSource::postSynchronouslyAndReturnError(
}
void MediaCodecSource::signalEOS(status_t err) {
- if (!mEncodedReachedEOS) {
- ALOGI("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
+ if (!mEncoderReachedEOS) {
+ ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
{
Mutex::Autolock autoLock(mOutputBufferLock);
// release all unread media buffers
@@ -496,16 +511,15 @@ void MediaCodecSource::signalEOS(status_t err) {
(*it)->release();
}
mOutputBufferQueue.clear();
- mEncodedReachedEOS = true;
+ mEncoderReachedEOS = true;
mErrorCode = err;
mOutputBufferCond.signal();
}
releaseEncoder();
}
- if (mStopping && reachedEOS()) {
- ALOGI("MediaCodecSource (%s) fully stopped",
- mIsVideo ? "video" : "audio");
+ if (mStopping && mEncoderReachedEOS) {
+ ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio");
// posting reply to everyone that's waiting
List<uint32_t>::iterator it;
for (it = mStopReplyIDQueue.begin();
@@ -755,7 +769,6 @@ status_t MediaCodecSource::onStart(MetaData *params) {
kWhatPullerNotify, mReflector->id());
err = mPuller->start(params, notify);
if (err != OK) {
- mPullerReachedEOS = true;
return err;
}
}
@@ -774,9 +787,9 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
CHECK(msg->findPointer("accessUnit", (void**)&mbuf));
if (mbuf == NULL) {
- ALOGI("puller (%s) reached EOS",
+ ALOGV("puller (%s) reached EOS",
mIsVideo ? "video" : "audio");
- mPullerReachedEOS = true;
+ signalEOS();
}
if (mEncoder == NULL) {
@@ -785,9 +798,8 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
if (mbuf != NULL) {
mbuf->release();
- } else {
- signalEOS();
}
+
break;
}
@@ -833,14 +845,14 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
}
case kWhatStop:
{
- ALOGI("MediaCodecSource (%s) stopping", mIsVideo ? "video" : "audio");
+ ALOGI("encoder (%s) stopping", mIsVideo ? "video" : "audio");
uint32_t replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
- if (reachedEOS()) {
+ if (mEncoderReachedEOS) {
// if we already reached EOS, reply and return now
- ALOGI("MediaCodecSource (%s) already stopped",
+ ALOGI("encoder (%s) already stopped",
mIsVideo ? "video" : "audio");
(new AMessage)->postReply(replyID);
break;
@@ -860,8 +872,6 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
if (mFlags & FLAG_USE_SURFACE_INPUT) {
mEncoder->signalEndOfInputStream();
} else {
- CHECK(mPuller != NULL);
- mPuller->stopAsync();
signalEOS();
}
break;