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

Commit ba7ec917 authored by Andreas Huber's avatar Andreas Huber
Browse files

Squashed commit of the following:

commit 427e927298449826bb5b98327b0c05957aa051e6
Author: Andreas Huber <andih@google.com>
Date:   Fri Feb 12 10:39:07 2010 -0800

    Fixing a race condition in AwesomePlayer and support for suspend/resume.

commit 96201a04b6657b6bd69ec6100f4de66aebcaa0b4
Author: Andreas Huber <andih@google.com>
Date:   Fri Feb 12 10:36:15 2010 -0800

    Protect MPEG4Source's sanity by properly locking.

related-to-bug: 2231576
parent 965e37ec
Loading
Loading
Loading
Loading
+123 −17
Original line number Diff line number Diff line
@@ -169,7 +169,8 @@ AwesomePlayer::AwesomePlayer()
      mAudioPlayer(NULL),
      mFlags(0),
      mLastVideoBuffer(NULL),
      mVideoBuffer(NULL) {
      mVideoBuffer(NULL),
      mSuspensionState(NULL) {
    CHECK_EQ(mClient.connect(), OK);

    DataSource::RegisterDefaultSniffers();
@@ -221,7 +222,11 @@ void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
status_t AwesomePlayer::setDataSource(
        const char *uri, const KeyedVector<String8, String8> *headers) {
    Mutex::Autolock autoLock(mLock);
    return setDataSource_l(uri, headers);
}

status_t AwesomePlayer::setDataSource_l(
        const char *uri, const KeyedVector<String8, String8> *headers) {
    reset_l();

    mUri = uri;
@@ -243,15 +248,22 @@ status_t AwesomePlayer::setDataSource(

    reset_l();

    sp<DataSource> source = new FileSource(fd, offset, length);
    sp<DataSource> dataSource = new FileSource(fd, offset, length);

    status_t err = source->initCheck();
    status_t err = dataSource->initCheck();

    if (err != OK) {
        return err;
    }

    sp<MediaExtractor> extractor = MediaExtractor::Create(source);
    mFileSource = dataSource;

    return setDataSource_l(dataSource);
}

status_t AwesomePlayer::setDataSource_l(
        const sp<DataSource> &dataSource) {
    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);

    if (extractor == NULL) {
        return UNKNOWN_ERROR;
@@ -299,6 +311,26 @@ void AwesomePlayer::reset_l() {

    cancelPlayerEvents();

    if (mPrefetcher != NULL) {
        CHECK_EQ(mPrefetcher->getStrongCount(), 1);
    }
    mPrefetcher.clear();

    // Shutdown audio first, so that the respone to the reset request
    // appears to happen instantaneously as far as the user is concerned
    // If we did this later, audio would continue playing while we
    // shutdown the video-related resources and the player appear to
    // not be as responsive to a reset request.
    mAudioSource.clear();

    if (mTimeSource != mAudioPlayer) {
        delete mTimeSource;
    }
    mTimeSource = NULL;

    delete mAudioPlayer;
    mAudioPlayer = NULL;

    mVideoRenderer.clear();

    if (mLastVideoBuffer) {
@@ -325,16 +357,6 @@ void AwesomePlayer::reset_l() {
        IPCThreadState::self()->flushCommands();
    }

    mAudioSource.clear();

    if (mTimeSource != mAudioPlayer) {
        delete mTimeSource;
    }
    mTimeSource = NULL;

    delete mAudioPlayer;
    mAudioPlayer = NULL;

    mDurationUs = -1;
    mFlags = 0;
    mVideoWidth = mVideoHeight = -1;
@@ -344,10 +366,13 @@ void AwesomePlayer::reset_l() {
    mSeeking = false;
    mSeekTimeUs = 0;

    mPrefetcher.clear();

    mUri.setTo("");
    mUriHeaders.clear();

    mFileSource.clear();

    delete mSuspensionState;
    mSuspensionState = NULL;
}

void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -403,7 +428,10 @@ void AwesomePlayer::onStreamDone() {

status_t AwesomePlayer::play() {
    Mutex::Autolock autoLock(mLock);
    return play_l();
}

status_t AwesomePlayer::play_l() {
    if (mFlags & PLAYING) {
        return OK;
    }
@@ -579,7 +607,10 @@ status_t AwesomePlayer::getDuration(int64_t *durationUs) {

status_t AwesomePlayer::getPosition(int64_t *positionUs) {
    Mutex::Autolock autoLock(mLock);
    return getPosition_l(positionUs);
}

status_t AwesomePlayer::getPosition_l(int64_t *positionUs) {
    if (mVideoSource != NULL) {
        *positionUs = mVideoTimeUs;
    } else if (mAudioPlayer != NULL) {
@@ -697,7 +728,11 @@ status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) {

void AwesomePlayer::onVideoEvent() {
    Mutex::Autolock autoLock(mLock);

    if (!mVideoEventPending) {
        // The event has been cancelled in reset_l() but had already
        // been scheduled for execution at that time.
        return;
    }
    mVideoEventPending = false;

    if (mSeeking) {
@@ -985,6 +1020,7 @@ void AwesomePlayer::onPrepareAsyncEvent() {

    if (prefetcher != NULL) {
        prefetcher->prepare();
        prefetcher.clear();
    }

    Mutex::Autolock autoLock(mLock);
@@ -1006,5 +1042,75 @@ void AwesomePlayer::onPrepareAsyncEvent() {
    mPreparedCondition.broadcast();
}

status_t AwesomePlayer::suspend() {
    LOGI("suspend");
    Mutex::Autolock autoLock(mLock);

    if (mSuspensionState != NULL) {
        return INVALID_OPERATION;
    }

    while (mFlags & PREPARING) {
        mPreparedCondition.wait(mLock);
    }

    SuspensionState *state = new SuspensionState;
    state->mUri = mUri;
    state->mUriHeaders = mUriHeaders;
    state->mFileSource = mFileSource;

    state->mFlags = mFlags & (PLAYING | LOOPING);
    getPosition_l(&state->mPositionUs);

    reset_l();

    mSuspensionState = state;

    return OK;
}

status_t AwesomePlayer::resume() {
    LOGI("resume");
    Mutex::Autolock autoLock(mLock);

    if (mSuspensionState == NULL) {
        return INVALID_OPERATION;
    }

    SuspensionState *state = mSuspensionState;
    mSuspensionState = NULL;

    status_t err;
    if (state->mFileSource != NULL) {
        err = setDataSource_l(state->mFileSource);

        if (err == OK) {
            mFileSource = state->mFileSource;
        }
    } else {
        err = setDataSource_l(state->mUri, &state->mUriHeaders);
    }

    if (err != OK) {
        delete state;
        state = NULL;

        return err;
    }

    seekTo_l(state->mPositionUs);

    mFlags = state->mFlags & LOOPING;

    if (state->mFlags & PLAYING) {
        play_l();
    }

    delete state;
    state = NULL;

    return OK;
}

}  // namespace android
+14 −0
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ protected:
    virtual ~MPEG4Source();

private:
    Mutex mLock;

    sp<MetaData> mFormat;
    sp<DataSource> mDataSource;
    int32_t mTimescale;
@@ -1300,6 +1302,8 @@ MPEG4Source::~MPEG4Source() {
}

status_t MPEG4Source::start(MetaData *params) {
    Mutex::Autolock autoLock(mLock);

    CHECK(!mStarted);

    int32_t val;
@@ -1325,6 +1329,8 @@ status_t MPEG4Source::start(MetaData *params) {
}

status_t MPEG4Source::stop() {
    Mutex::Autolock autoLock(mLock);

    CHECK(mStarted);

    if (mBuffer != NULL) {
@@ -1345,6 +1351,8 @@ status_t MPEG4Source::stop() {
}

sp<MetaData> MPEG4Source::getFormat() {
    Mutex::Autolock autoLock(mLock);

    return mFormat;
}

@@ -1369,6 +1377,8 @@ size_t MPEG4Source::parseNALSize(const uint8_t *data) const {

status_t MPEG4Source::read(
        MediaBuffer **out, const ReadOptions *options) {
    Mutex::Autolock autoLock(mLock);

    CHECK(mStarted);

    *out = NULL;
@@ -1428,6 +1438,7 @@ status_t MPEG4Source::read(
                return ERROR_IO;
            }

            CHECK(mBuffer != NULL);
            mBuffer->set_range(0, size);
            mBuffer->meta_data()->clear();
            mBuffer->meta_data()->setInt64(
@@ -1461,8 +1472,10 @@ status_t MPEG4Source::read(
        }

        MediaBuffer *clone = mBuffer->clone();
        CHECK(clone != NULL);
        clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);

        CHECK(mBuffer != NULL);
        mBuffer->set_range(
                mBuffer->range_offset() + mNALLengthSize + nal_size,
                mBuffer->range_length() - mNALLengthSize - nal_size);
@@ -1521,6 +1534,7 @@ status_t MPEG4Source::read(
        }
        CHECK_EQ(srcOffset, size);

        CHECK(mBuffer != NULL);
        mBuffer->set_range(0, dstOffset);
        mBuffer->meta_data()->clear();
        mBuffer->meta_data()->setInt64(
+30 −10
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ namespace android {

struct PrefetchedSource : public MediaSource {
    PrefetchedSource(
            const sp<Prefetcher> &prefetcher,
            size_t index,
            const sp<MediaSource> &source);

@@ -52,13 +51,13 @@ private:
    Mutex mLock;
    Condition mCondition;

    sp<Prefetcher> mPrefetcher;
    sp<MediaSource> mSource;
    size_t mIndex;
    bool mStarted;
    bool mReachedEOS;
    int64_t mSeekTimeUs;
    int64_t mCacheDurationUs;
    bool mPrefetcherStopped;

    List<MediaBuffer *> mCachedBuffers;

@@ -69,6 +68,7 @@ private:
    void clearCache_l();

    void cacheMore();
    void onPrefetcherStopped();

    PrefetchedSource(const PrefetchedSource &);
    PrefetchedSource &operator=(const PrefetchedSource &);
@@ -88,7 +88,7 @@ sp<MediaSource> Prefetcher::addSource(const sp<MediaSource> &source) {
    Mutex::Autolock autoLock(mLock);

    sp<PrefetchedSource> psource =
        new PrefetchedSource(this, mSources.size(), source);
        new PrefetchedSource(mSources.size(), source);

    mSources.add(psource);

@@ -130,8 +130,6 @@ void Prefetcher::threadFunc() {
    for (;;) {
        Mutex::Autolock autoLock(mLock);
        if (mDone) {
            mThreadExited = true;
            mCondition.signal();
            break;
        }
        mCondition.waitRelative(mLock, 10000000ll);
@@ -169,6 +167,19 @@ void Prefetcher::threadFunc() {
            source->cacheMore();
        }
    }

    for (size_t i = 0; i < mSources.size(); ++i) {
        sp<PrefetchedSource> source = mSources[i].promote();

        if (source == NULL) {
            continue;
        }

        source->onPrefetcherStopped();
    }

    mThreadExited = true;
    mCondition.signal();
}

int64_t Prefetcher::getCachedDurationUs(bool *noMoreData) {
@@ -219,16 +230,15 @@ status_t Prefetcher::prepare() {
////////////////////////////////////////////////////////////////////////////////

PrefetchedSource::PrefetchedSource(
        const sp<Prefetcher> &prefetcher,
        size_t index,
        const sp<MediaSource> &source)
    : mPrefetcher(prefetcher),
      mSource(source),
    : mSource(source),
      mIndex(index),
      mStarted(false),
      mReachedEOS(false),
      mSeekTimeUs(0),
      mCacheDurationUs(0) {
      mCacheDurationUs(0),
      mPrefetcherStopped(false) {
}

PrefetchedSource::~PrefetchedSource() {
@@ -238,6 +248,8 @@ PrefetchedSource::~PrefetchedSource() {
}

status_t PrefetchedSource::start(MetaData *params) {
    CHECK(!mStarted);

    Mutex::Autolock autoLock(mLock);

    status_t err = mSource->start(params);
@@ -252,6 +264,8 @@ status_t PrefetchedSource::start(MetaData *params) {
}

status_t PrefetchedSource::stop() {
    CHECK(mStarted);

    Mutex::Autolock autoLock(mLock);

    clearCache_l();
@@ -281,7 +295,7 @@ status_t PrefetchedSource::read(
        mSeekTimeUs = seekTimeUs;
    }

    while (!mReachedEOS && mCachedBuffers.empty()) {
    while (!mPrefetcherStopped && !mReachedEOS && mCachedBuffers.empty()) {
        mCondition.wait(mLock);
    }

@@ -390,4 +404,10 @@ void PrefetchedSource::clearCache_l() {
    updateCacheDuration_l();
}

void PrefetchedSource::onPrefetcherStopped() {
    Mutex::Autolock autoLock(mLock);
    mPrefetcherStopped = true;
    mCondition.signal();
}

}  // namespace android
+23 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
namespace android {

struct AudioPlayer;
struct DataSource;
struct MediaBuffer;
struct MediaExtractor;
struct MediaSource;
@@ -78,6 +79,9 @@ struct AwesomePlayer {

    status_t getVideoDimensions(int32_t *width, int32_t *height) const;

    status_t suspend();
    status_t resume();

private:
    friend struct AwesomeEvent;

@@ -103,6 +107,8 @@ private:
    String8 mUri;
    KeyedVector<String8, String8> mUriHeaders;

    sp<DataSource> mFileSource;

    sp<MediaSource> mVideoSource;
    sp<AwesomeRenderer> mVideoRenderer;

@@ -140,12 +146,29 @@ private:
    void postBufferingEvent_l();
    void postStreamDoneEvent_l();
    void postCheckAudioStatusEvent_l();
    status_t getPosition_l(int64_t *positionUs);
    status_t play_l();

    MediaBuffer *mLastVideoBuffer;
    MediaBuffer *mVideoBuffer;

    sp<Prefetcher> mPrefetcher;

    struct SuspensionState {
        String8 mUri;
        KeyedVector<String8, String8> mUriHeaders;
        sp<DataSource> mFileSource;

        uint32_t mFlags;
        int64_t mPositionUs;

    } *mSuspensionState;

    status_t setDataSource_l(
            const char *uri,
            const KeyedVector<String8, String8> *headers = NULL);

    status_t setDataSource_l(const sp<DataSource> &dataSource);
    status_t setDataSource_l(const sp<MediaExtractor> &extractor);
    void reset_l();
    status_t seekTo_l(int64_t timeUs);