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

Commit 6be780eb authored by Andreas Huber's avatar Andreas Huber
Browse files

Properly implement asynchronous preparation of media playback.

related-to-bug: 2413002
parent a2292790
Loading
Loading
Loading
Loading
+2 −21
Original line number Diff line number Diff line
@@ -49,30 +49,11 @@ status_t StagefrightPlayer::setVideoSurface(const sp<ISurface> &surface) {
}

status_t StagefrightPlayer::prepare() {
    LOGV("prepare");

    int32_t width, height;
    if (mPlayer->getVideoDimensions(&width, &height) != OK) {
        width = height = 0;
    }

    sendEvent(MEDIA_SET_VIDEO_SIZE, width, height);

    return OK;
    return mPlayer->prepare();
}

status_t StagefrightPlayer::prepareAsync() {
    LOGV("prepareAsync");

    status_t err = prepare();

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

    sendEvent(MEDIA_PREPARED);

    return OK;
    return mPlayer->prepareAsync();
}

status_t StagefrightPlayer::start() {
+76 −22
Original line number Diff line number Diff line
@@ -37,21 +37,23 @@
namespace android {

struct AwesomeEvent : public TimedEventQueue::Event {
    AwesomeEvent(AwesomePlayer *player, int32_t code)
    AwesomeEvent(
            AwesomePlayer *player,
            void (AwesomePlayer::*method)())
        : mPlayer(player),
          mCode(code) {
          mMethod(method) {
    }

protected:
    virtual ~AwesomeEvent() {}

    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
        mPlayer->onEvent(mCode);
        (mPlayer->*mMethod)();
    }

private:
    AwesomePlayer *mPlayer;
    int32_t mCode;
    void (AwesomePlayer::*mMethod)();

    AwesomeEvent(const AwesomeEvent &);
    AwesomeEvent &operator=(const AwesomeEvent &);
@@ -115,13 +117,16 @@ AwesomePlayer::AwesomePlayer()

    DataSource::RegisterDefaultSniffers();

    mVideoEvent = new AwesomeEvent(this, 0);
    mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent);
    mVideoEventPending = false;
    mStreamDoneEvent = new AwesomeEvent(this, 1);
    mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone);
    mStreamDoneEventPending = false;
    mBufferingEvent = new AwesomeEvent(this, 2);
    mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate);
    mBufferingEventPending = false;
    mCheckAudioStatusEvent = new AwesomeEvent(this, 3);

    mCheckAudioStatusEvent = new AwesomeEvent(
            this, &AwesomePlayer::onCheckAudioStatus);

    mAudioStatusEventPending = false;

    mQueue.start();
@@ -287,12 +292,12 @@ void AwesomePlayer::reset_l() {
    mPrefetcher.clear();
}

void AwesomePlayer::notifyListener_l(int msg, int ext1) {
void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
    if (mListener != NULL) {
        sp<MediaPlayerBase> listener = mListener.promote();

        if (listener != NULL) {
            listener->sendEvent(msg, ext1);
            listener->sendEvent(msg, ext1, ext2);
        }
    }
}
@@ -623,18 +628,7 @@ status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) {
    return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
}

void AwesomePlayer::onEvent(int32_t code) {
    if (code == 1) {
        onStreamDone();
        return;
    } else if (code == 2) {
        onBufferingUpdate();
        return;
    } else if (code == 3) {
        onCheckAudioStatus();
        return;
    }

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

    mVideoEventPending = false;
@@ -819,5 +813,65 @@ void AwesomePlayer::onCheckAudioStatus() {
    postCheckAudioStatusEvent_l();
}

status_t AwesomePlayer::prepare() {
    Mutex::Autolock autoLock(mLock);

    status_t err = prepareAsync_l();

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

    while (mAsyncPrepareEvent != NULL) {
        mPreparedCondition.wait(mLock);
    }

    return OK;
}

status_t AwesomePlayer::prepareAsync() {
    Mutex::Autolock autoLock(mLock);
    return prepareAsync_l();
}

status_t AwesomePlayer::prepareAsync_l() {
    if (mAsyncPrepareEvent != NULL) {
        return UNKNOWN_ERROR;  // async prepare already pending.
    }

    mAsyncPrepareEvent = new AwesomeEvent(
            this, &AwesomePlayer::onPrepareAsyncEvent);

    mQueue.postEvent(mAsyncPrepareEvent);

    return OK;
}

void AwesomePlayer::onPrepareAsyncEvent() {
    sp<Prefetcher> prefetcher;

    {
        Mutex::Autolock autoLock(mLock);
        prefetcher = mPrefetcher;
    }

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

    Mutex::Autolock autoLock(mLock);

    if (mVideoWidth < 0 || mVideoHeight < 0) {
        notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
    } else {
        notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
    }

    notifyListener_l(MEDIA_PREPARED);

    mAsyncPrepareEvent = NULL;
    mPreparedCondition.signal();
}

}  // namespace android
+17 −10
Original line number Diff line number Diff line
@@ -171,7 +171,7 @@ void Prefetcher::threadFunc() {
    }
}

int64_t Prefetcher::getCachedDurationUs() {
int64_t Prefetcher::getCachedDurationUs(bool *noMoreData) {
    Mutex::Autolock autoLock(mLock);

    int64_t minCacheDurationUs = -1;
@@ -197,9 +197,25 @@ int64_t Prefetcher::getCachedDurationUs() {
        }
    }

    if (noMoreData) {
        *noMoreData = minCacheDurationUs < 0;
    }

    return minCacheDurationUs < 0 ? 0 : minCacheDurationUs;
}

status_t Prefetcher::prepare() {
    // Buffer about 2 secs worth of data on prepare.

    int64_t duration;
    bool noMoreData;
    do {
        duration = getCachedDurationUs(&noMoreData);
    } while (!noMoreData && duration < 2000000);

    return OK;
}

////////////////////////////////////////////////////////////////////////////////

PrefetchedSource::PrefetchedSource(
@@ -232,15 +248,6 @@ status_t PrefetchedSource::start(MetaData *params) {

    mStarted = true;

    for (;;) {
        // Buffer 2 secs on startup.
        if (mReachedEOS || mCacheDurationUs > 2000000) {
            break;
        }

        mCondition.wait(mLock);
    }

    return OK;
}

+10 −2
Original line number Diff line number Diff line
@@ -57,6 +57,10 @@ struct AwesomePlayer {

    void reset();

    status_t prepare();
    status_t prepareAsync();
    status_t prepareAsync_l();

    status_t play();
    status_t pause();

@@ -121,6 +125,9 @@ private:
    sp<TimedEventQueue::Event> mCheckAudioStatusEvent;
    bool mAudioStatusEventPending;

    sp<TimedEventQueue::Event> mAsyncPrepareEvent;
    Condition mPreparedCondition;

    void postVideoEvent_l(int64_t delayUs = -1);
    void postBufferingEvent_l();
    void postStreamDoneEvent_l();
@@ -143,13 +150,14 @@ private:
    status_t setAudioSource(sp<MediaSource> source);
    status_t setVideoSource(sp<MediaSource> source);

    void onEvent(int32_t code);
    void onStreamDone();

    void notifyListener_l(int msg, int ext1 = 0);
    void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);

    void onVideoEvent();
    void onBufferingUpdate();
    void onCheckAudioStatus();
    void onPrepareAsyncEvent();

    AwesomePlayer(const AwesomePlayer &);
    AwesomePlayer &operator=(const AwesomePlayer &);
+3 −1
Original line number Diff line number Diff line
@@ -34,7 +34,9 @@ struct Prefetcher : public RefBase {
    // that will benefit from prefetching/caching the original one.
    sp<MediaSource> addSource(const sp<MediaSource> &source);

    int64_t getCachedDurationUs();
    int64_t getCachedDurationUs(bool *noMoreData = NULL);

    status_t prepare();

protected:
    virtual ~Prefetcher();