Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2abde2c1 authored by Andy Hung's avatar Andy Hung
Browse files

NuPlayer: Fix flush mode decoder error handling

Explicitly handle each flush mode upon decoder error.
Do not clear out affected decoder immediately.
Alter logcat messages for better diagnostics.

Bug: 17638878
Bug: 17679341
Change-Id: I219796c04d65d7c4dd61c0d4f99f9f580241a68b
parent 955e24d3
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ void NuPlayer::GenericSource::resetDataSource() {
    mDecryptHandle = NULL;
    mDrmManagerClient = NULL;
    mStarted = false;
    mStopRead = true;
}

status_t NuPlayer::GenericSource::setDataSource(
@@ -439,6 +440,7 @@ status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
void NuPlayer::GenericSource::start() {
    ALOGI("start");

    mStopRead = false;
    if (mAudioTrack.mSource != NULL) {
        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);

@@ -459,6 +461,12 @@ void NuPlayer::GenericSource::stop() {
    // nothing to do, just account for DRM playback status
    setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
    mStarted = false;
    if (mIsWidevine) {
        // For a widevine source we need to prevent any further reads.
        sp<AMessage> msg = new AMessage(kWhatStopWidevine, id());
        sp<AMessage> response;
        (void) msg->postAndAwaitResponse(&response);
    }
}

void NuPlayer::GenericSource::pause() {
@@ -675,6 +683,20 @@ void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
          break;
      }

      case kWhatStopWidevine:
      {
          // mStopRead is only used for Widevine to prevent the video source
          // from being read while the associated video decoder is shutting down.
          mStopRead = true;
          if (mVideoTrack.mSource != NULL) {
              mVideoTrack.mPackets->clear();
          }
          sp<AMessage> response = new AMessage;
          uint32_t replyID;
          CHECK(msg->senderAwaitsResponse(&replyID));
          response->postReply(replyID);
          break;
      }
      default:
          Source::onMessageReceived(msg);
          break;
@@ -1082,6 +1104,11 @@ void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
}

status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
    // If the Widevine source is stopped, do not attempt to read any
    // more buffers.
    if (mStopRead) {
        return INVALID_OPERATION;
    }
    if (mVideoTrack.mSource != NULL) {
        int64_t actualTimeUs;
        readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
@@ -1193,6 +1220,10 @@ void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {

void NuPlayer::GenericSource::readBuffer(
        media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
    // Do not read data if Widevine source is stopped
    if (mStopRead) {
        return;
    }
    Track *track;
    size_t maxBuffers = 1;
    switch (trackType) {
+2 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ private:
        kWhatSelectTrack,
        kWhatSeek,
        kWhatReadBuffer,
        kWhatStopWidevine,
    };

    Vector<sp<MediaSource> > mSources;
@@ -131,6 +132,7 @@ private:
    DrmManagerClient *mDrmManagerClient;
    sp<DecryptHandle> mDecryptHandle;
    bool mStarted;
    bool mStopRead;
    String8 mContentType;
    AString mSniffedMIME;
    off64_t mMetaDataSize;
+45 −20
Original line number Diff line number Diff line
@@ -791,6 +791,11 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                    ALOGV("initiating %s decoder shutdown",
                         audio ? "audio" : "video");

                    // Widevine source reads must stop before releasing the video decoder.
                    if (!audio && mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
                        mSource->stop();
                    }

                    getDecoder(audio)->initiateShutdown();

                    if (audio) {
@@ -833,30 +838,50 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                finishFlushIfPossible();
            } else if (what == Decoder::kWhatError) {
                status_t err;
                if (!msg->findInt32("err", &err)) {
                if (!msg->findInt32("err", &err) || err == OK) {
                    err = UNKNOWN_ERROR;
                }
                ALOGE("received error from %s decoder %#x", audio ? "audio" : "video", err);

                ALOGI("shutting down %s", audio ? "audio" : "video");
                if (audio && mFlushingAudio != NONE) {
                    mRenderer->queueEOS(audio, err);
                    mAudioDecoder.clear();
                    ++mAudioDecoderGeneration;
                    mFlushingAudio = SHUT_DOWN;
                    finishFlushIfPossible();
                } else if (!audio && mFlushingVideo != NONE) {
                    mRenderer->queueEOS(audio, err);
                    mVideoDecoder.clear();
                    ++mVideoDecoderGeneration;
                    mFlushingVideo = SHUT_DOWN;
                    finishFlushIfPossible();
                }  else {
                // 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).
                //
                // We try to gracefully shut down the affected decoder if possible,
                // rather than trying to force the shutdown with something
                // similar to performReset(). This method can lead to a hang
                // if MediaCodec functions block after an error, but they should
                // typically return INVALID_OPERATION instead of blocking.

                FlushStatus *flushing = audio ? &mFlushingAudio : &mFlushingVideo;
                ALOGE("received error(%#x) from %s decoder, flushing(%d), now shutting down",
                        err, audio ? "audio" : "video", *flushing);

                switch (*flushing) {
                    case NONE:
                        mDeferredActions.push_back(
                                new ShutdownDecoderAction(audio, !audio /* video */));
                        processDeferredActions();
                    notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
                        break;
                    case FLUSHING_DECODER:
                        *flushing = FLUSHING_DECODER_SHUTDOWN; // initiate shutdown after flush.
                        break; // Wait for flush to complete.
                    case FLUSHING_DECODER_SHUTDOWN:
                        break; // Wait for flush to complete.
                    case SHUTTING_DOWN_DECODER:
                        break; // Wait for shutdown to complete.
                    case FLUSHED:
                        // Widevine source reads must stop before releasing the video decoder.
                        if (!audio && mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
                            mSource->stop();
                        }
                        getDecoder(audio)->initiateShutdown(); // In the middle of a seek.
                        *flushing = SHUTTING_DOWN_DECODER;     // Shut down.
                        break;
                    case SHUT_DOWN:
                        finishFlushIfPossible();  // Should not occur.
                        break;                    // Finish anyways.
                }
                notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
            } else if (what == Decoder::kWhatDrainThisBuffer) {
                renderBuffer(audio, msg);
            } else {
+7 −3
Original line number Diff line number Diff line
@@ -140,6 +140,8 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
            format, surface, NULL /* crypto */, 0 /* flags */);
    if (err != OK) {
        ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
        mCodec->release();
        mCodec.clear();
        handleError(err);
        return;
    }
@@ -152,6 +154,8 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
    err = mCodec->start();
    if (err != OK) {
        ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
        mCodec->release();
        mCodec.clear();
        handleError(err);
        return;
    }
@@ -511,9 +515,9 @@ void NuPlayer::Decoder::onFlush() {
    if (err != OK) {
        ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
        handleError(err);
        return;
        // finish with posting kWhatFlushCompleted.
        // we attempt to release the buffers even if flush fails.
    }

    releaseAndResetMediaBuffers();

    sp<AMessage> notify = mNotify->dup();
@@ -551,7 +555,7 @@ void NuPlayer::Decoder::onShutdown() {
    if (err != OK) {
        ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
        handleError(err);
        return;
        // finish with posting kWhatShutdownCompleted.
    }

    sp<AMessage> notify = mNotify->dup();
+16 −3
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>

namespace android {

@@ -47,6 +48,7 @@ NuPlayerDriver::NuPlayerDriver()
      mLooping(false),
      mAutoLoop(false),
      mStartupSeekTimeUs(-1) {
    ALOGV("NuPlayerDriver(%p)", this);
    mLooper->setName("NuPlayerDriver Looper");

    mLooper->start(
@@ -61,6 +63,7 @@ NuPlayerDriver::NuPlayerDriver()
}

NuPlayerDriver::~NuPlayerDriver() {
    ALOGV("~NuPlayerDriver(%p)", this);
    mLooper->stop();
}

@@ -78,9 +81,9 @@ status_t NuPlayerDriver::setDataSource(
        const sp<IMediaHTTPService> &httpService,
        const char *url,
        const KeyedVector<String8, String8> *headers) {
    ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
    Mutex::Autolock autoLock(mLock);

    ALOGV("setDataSource: url=%s", url);
    if (mState != STATE_IDLE) {
        return INVALID_OPERATION;
    }
@@ -97,9 +100,9 @@ status_t NuPlayerDriver::setDataSource(
}

status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
    ALOGV("setDataSource(%p) file(%d)", this, fd);
    Mutex::Autolock autoLock(mLock);

    ALOGV("setDataSource: fd=%d", fd);
    if (mState != STATE_IDLE) {
        return INVALID_OPERATION;
    }
@@ -116,9 +119,9 @@ status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
}

status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
    ALOGV("setDataSource(%p) stream source", this);
    Mutex::Autolock autoLock(mLock);

    ALOGV("setDataSource: stream source");
    if (mState != STATE_IDLE) {
        return INVALID_OPERATION;
    }
@@ -136,6 +139,7 @@ status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {

status_t NuPlayerDriver::setVideoSurfaceTexture(
        const sp<IGraphicBufferProducer> &bufferProducer) {
    ALOGV("setVideoSurfaceTexture(%p)", this);
    Mutex::Autolock autoLock(mLock);

    if (mSetSurfaceInProgress) {
@@ -163,6 +167,7 @@ status_t NuPlayerDriver::setVideoSurfaceTexture(
}

status_t NuPlayerDriver::prepare() {
    ALOGV("prepare(%p)", this);
    Mutex::Autolock autoLock(mLock);
    return prepare_l();
}
@@ -197,6 +202,7 @@ status_t NuPlayerDriver::prepare_l() {
}

status_t NuPlayerDriver::prepareAsync() {
    ALOGV("prepareAsync(%p)", this);
    Mutex::Autolock autoLock(mLock);

    switch (mState) {
@@ -218,6 +224,7 @@ status_t NuPlayerDriver::prepareAsync() {
}

status_t NuPlayerDriver::start() {
    ALOGD("start(%p)", this);
    Mutex::Autolock autoLock(mLock);

    switch (mState) {
@@ -292,6 +299,7 @@ status_t NuPlayerDriver::start() {
}

status_t NuPlayerDriver::stop() {
    ALOGD("stop(%p)", this);
    Mutex::Autolock autoLock(mLock);

    switch (mState) {
@@ -346,6 +354,7 @@ bool NuPlayerDriver::isPlaying() {
}

status_t NuPlayerDriver::seekTo(int msec) {
    ALOGD("seekTo(%p) %d ms", this, msec);
    Mutex::Autolock autoLock(mLock);

    int64_t seekTimeUs = msec * 1000ll;
@@ -430,6 +439,7 @@ status_t NuPlayerDriver::getDuration(int *msec) {
}

status_t NuPlayerDriver::reset() {
    ALOGD("reset(%p)", this);
    Mutex::Autolock autoLock(mLock);

    switch (mState) {
@@ -572,6 +582,7 @@ status_t NuPlayerDriver::getMetadata(
}

void NuPlayerDriver::notifyResetComplete() {
    ALOGI("notifyResetComplete(%p)", this);
    Mutex::Autolock autoLock(mLock);

    CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
@@ -580,6 +591,7 @@ void NuPlayerDriver::notifyResetComplete() {
}

void NuPlayerDriver::notifySetSurfaceComplete() {
    ALOGV("notifySetSurfaceComplete(%p)", this);
    Mutex::Autolock autoLock(mLock);

    CHECK(mSetSurfaceInProgress);
@@ -602,6 +614,7 @@ void NuPlayerDriver::notifyPosition(int64_t positionUs) {
}

void NuPlayerDriver::notifySeekComplete() {
    ALOGV("notifySeekComplete(%p)", this);
    Mutex::Autolock autoLock(mLock);
    notifySeekComplete_l();
}
Loading