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

Commit d5923409 authored by Lajos Molnar's avatar Lajos Molnar
Browse files

mediaplayer: limit scheduling video frames into the future

This addresses when video timestamps jumps before an audio timestamp,
but still works on slideshow video clips (<=1fps).

This, however, will not skip time-changes on video-only live video
streams, as we cannot distinguish live slideshow video clips from
non-slideshow ones.

Bug: 18032127
Change-Id: I959a714edfe1c8cf3b84704c693dcd1b3e5b7855
parent eecb7805
Loading
Loading
Loading
Loading
+38 −1
Original line number Diff line number Diff line
@@ -82,7 +82,9 @@ NuPlayer::Renderer::Renderer(
      mAudioRenderingStartGeneration(0),
      mAudioOffloadPauseTimeoutGeneration(0),
      mAudioOffloadTornDown(false),
      mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER) {
      mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
      mTotalBuffersQueued(0),
      mLastAudioBufferDrained(0) {
    readProperties();
}

@@ -361,6 +363,19 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
            break;
        }

        case kWhatPostDrainVideoQueue:
        {
            int32_t generation;
            CHECK(msg->findInt32("generation", &generation));
            if (generation != mVideoQueueGeneration) {
                break;
            }

            mDrainVideoQueuePending = false;
            postDrainVideoQueue();
            break;
        }

        case kWhatQueueBuffer:
        {
            onQueueBuffer(msg);
@@ -580,6 +595,8 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
    while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
        QueueEntry *entry = &*mAudioQueue.begin();

        mLastAudioBufferDrained = entry->mBufferOrdinal;

        if (entry->mBuffer == NULL) {
            // EOS
            int64_t postEOSDelayUs = 0;
@@ -716,6 +733,25 @@ void NuPlayer::Renderer::postDrainVideoQueue() {
        } else {
            realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
        }

        // Heuristics to handle situation when media time changed without a
        // discontinuity. If we have not drained an audio buffer that was
        // received after this buffer, repost in 10 msec. Otherwise repost
        // in 500 msec.
        delayUs = realTimeUs - nowUs;
        if (delayUs > 500000) {
            int64_t postDelayUs = 500000;
            if (mHasAudio && (mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0) {
                postDelayUs = 10000;
            }
            msg->setWhat(kWhatPostDrainVideoQueue);
            msg->post(postDelayUs);
            mVideoScheduler->restart();
            ALOGI("possible video time jump of %dms, retrying in %dms",
                    (int)(delayUs / 1000), (int)(postDelayUs / 1000));
            mDrainVideoQueuePending = true;
            return;
        }
    }

    realTimeUs = mVideoScheduler->schedule(realTimeUs * 1000) / 1000;
@@ -855,6 +891,7 @@ void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
    entry.mNotifyConsumed = notifyConsumed;
    entry.mOffset = 0;
    entry.mFinalResult = OK;
    entry.mBufferOrdinal = ++mTotalBuffersQueued;

    if (audio) {
        Mutex::Autolock autoLock(mLock);
+5 −0
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ private:
    enum {
        kWhatDrainAudioQueue     = 'draA',
        kWhatDrainVideoQueue     = 'draV',
        kWhatPostDrainVideoQueue = 'pDVQ',
        kWhatQueueBuffer         = 'queB',
        kWhatQueueEOS            = 'qEOS',
        kWhatFlush               = 'flus',
@@ -119,6 +120,7 @@ private:
        sp<AMessage> mNotifyConsumed;
        size_t mOffset;
        status_t mFinalResult;
        int32_t mBufferOrdinal;
    };

    static const int64_t kMinPositionUpdateDelayUs;
@@ -169,6 +171,9 @@ private:
    bool mAudioOffloadTornDown;
    audio_offload_info_t mCurrentOffloadInfo;

    int32_t mTotalBuffersQueued;
    int32_t mLastAudioBufferDrained;

    size_t fillAudioBuffer(void *buffer, size_t size);

    bool onDrainAudioQueue();