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

Commit 078cfcf7 authored by Andreas Huber's avatar Andreas Huber
Browse files

Various improvements to nuplayer playback

- Drastically cut down the number of times we supply the AudioSink with data
by estimating the time until the sink would run out of data and then scheduling
a refill in advance of that.

- Use a dedicated looper for video decoders since they are currently taking
too long to return from OMX_FillThisBuffer (bug 5325201)

- Revise thread priorities for the OMX dispatcher and software codecs, instead
of running them at ANDROID_PRIORITY_AUDIO, they now only run at
ANDROID_PRIORITY_FOREGROUND

- Since threads created by pthread_create inherit all of the parent threads
attributes including thread priority, briefly reset thread priority to
ANDROID_PRIORITY_FOREGROUND before instantiating OMX components and then
restore it.

Change-Id: If9332a3a20dad5485333d68c11de0d2d5d3fffc3
parent 5dc2812a
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -299,7 +299,12 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                         sampleRate, numChannels);

                    mAudioSink->close();
                    CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
                    CHECK_EQ(mAudioSink->open(
                                sampleRate,
                                numChannels,
                                AUDIO_FORMAT_PCM_16_BIT,
                                8 /* bufferCount */),
                             (status_t)OK);
                    mAudioSink->start();

                    mRenderer->signalAudioSinkChanged();
+13 −13
Original line number Diff line number Diff line
@@ -70,19 +70,19 @@ private:
    struct StreamingSource;

    enum {
        kWhatSetDataSource,
        kWhatSetVideoNativeWindow,
        kWhatSetAudioSink,
        kWhatMoreDataQueued,
        kWhatStart,
        kWhatScanSources,
        kWhatVideoNotify,
        kWhatAudioNotify,
        kWhatRendererNotify,
        kWhatReset,
        kWhatSeek,
        kWhatPause,
        kWhatResume,
        kWhatSetDataSource              = '=DaS',
        kWhatSetVideoNativeWindow       = '=NaW',
        kWhatSetAudioSink               = '=AuS',
        kWhatMoreDataQueued             = 'more',
        kWhatStart                      = 'strt',
        kWhatScanSources                = 'scan',
        kWhatVideoNotify                = 'vidN',
        kWhatAudioNotify                = 'audN',
        kWhatRendererNotify             = 'renN',
        kWhatReset                      = 'rset',
        kWhatSeek                       = 'seek',
        kWhatPause                      = 'paus',
        kWhatResume                     = 'rsme',
    };

    wp<NuPlayerDriver> mDriver;
+14 −1
Original line number Diff line number Diff line
@@ -59,8 +59,21 @@ void NuPlayer::Decoder::configure(const sp<MetaData> &meta) {
        format->setObject("native-window", mNativeWindow);
    }

    // Current video decoders do not return from OMX_FillThisBuffer
    // quickly, violating the OpenMAX specs, until that is remedied
    // we need to invest in an extra looper to free the main event
    // queue.
    bool needDedicatedLooper = !strncasecmp(mime, "video/", 6);

    mCodec = new ACodec;
    looper()->registerHandler(mCodec);

    if (needDedicatedLooper && mCodecLooper == NULL) {
        mCodecLooper = new ALooper;
        mCodecLooper->setName("NuPlayerDecoder");
        mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
    }

    (needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec);

    mCodec->setNotificationMessage(notifyMsg);
    mCodec->initiateSetup(format);
+2 −1
Original line number Diff line number Diff line
@@ -43,13 +43,14 @@ protected:

private:
    enum {
        kWhatCodecNotify,
        kWhatCodecNotify        = 'cdcN',
    };

    sp<AMessage> mNotify;
    sp<NativeWindowWrapper> mNativeWindow;

    sp<ACodec> mCodec;
    sp<ALooper> mCodecLooper;

    Vector<sp<ABuffer> > mCSD;
    size_t mCSDIndex;
+53 −26
Original line number Diff line number Diff line
@@ -118,9 +118,24 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {

            mDrainAudioQueuePending = false;

            onDrainAudioQueue();
            if (onDrainAudioQueue()) {
                uint32_t numFramesPlayed;
                CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
                         (status_t)OK);

            postDrainAudioQueue();
                uint32_t numFramesPendingPlayout =
                    mNumFramesWritten - numFramesPlayed;

                // This is how long the audio sink will have data to
                // play back.
                int64_t delayUs =
                    mAudioSink->msecsPerFrame()
                        * numFramesPendingPlayout * 1000ll;

                // Let's give it more data after about half that time
                // has elapsed.
                postDrainAudioQueue(delayUs / 2);
            }
            break;
        }

@@ -182,7 +197,7 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
    }
}

void NuPlayer::Renderer::postDrainAudioQueue() {
void NuPlayer::Renderer::postDrainAudioQueue(int64_t delayUs) {
    if (mDrainAudioQueuePending || mSyncQueues || mPaused) {
        return;
    }
@@ -194,19 +209,33 @@ void NuPlayer::Renderer::postDrainAudioQueue() {
    mDrainAudioQueuePending = true;
    sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
    msg->setInt32("generation", mAudioQueueGeneration);
    msg->post();
    msg->post(delayUs);
}

void NuPlayer::Renderer::signalAudioSinkChanged() {
    (new AMessage(kWhatAudioSinkChanged, id()))->post();
}

void NuPlayer::Renderer::onDrainAudioQueue() {
    for (;;) {
        if (mAudioQueue.empty()) {
            break;
bool NuPlayer::Renderer::onDrainAudioQueue() {
    uint32_t numFramesPlayed;
    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);

    ssize_t numFramesAvailableToWrite =
        mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);

#if 0
    if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
        LOGI("audio sink underrun");
    } else {
        LOGV("audio queue has %d frames left to play",
             mAudioSink->frameCount() - numFramesAvailableToWrite);
    }
#endif

    size_t numBytesAvailableToWrite =
        numFramesAvailableToWrite * mAudioSink->frameSize();

    while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
        QueueEntry *entry = &*mAudioQueue.begin();

        if (entry->mBuffer == NULL) {
@@ -216,20 +245,7 @@ void NuPlayer::Renderer::onDrainAudioQueue() {

            mAudioQueue.erase(mAudioQueue.begin());
            entry = NULL;
            return;
        }

        uint32_t numFramesPlayed;
        CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);

        ssize_t numFramesAvailableToWrite =
            mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);

        size_t numBytesAvailableToWrite =
            numFramesAvailableToWrite * mAudioSink->frameSize();

        if (numBytesAvailableToWrite == 0) {
            break;
            return false;
        }

        if (entry->mOffset == 0) {
@@ -274,10 +290,14 @@ void NuPlayer::Renderer::onDrainAudioQueue() {
            entry = NULL;
        }

        mNumFramesWritten += copy / mAudioSink->frameSize();
        numBytesAvailableToWrite -= copy;
        size_t copiedFrames = copy / mAudioSink->frameSize();
        mNumFramesWritten += copiedFrames;
    }

    notifyPosition();

    return !mAudioQueue.empty();
}

void NuPlayer::Renderer::postDrainVideoQueue() {
@@ -344,7 +364,14 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
    int64_t mediaTimeUs;
    CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));

    LOGI("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
    int64_t realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
    int64_t lateByUs = ALooper::GetNowUs() - realTimeUs;

    if (lateByUs > 40000) {
        LOGI("video late by %lld us (%.2f secs)", lateByUs, lateByUs / 1E6);
    } else {
        LOGV("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
    }
#endif

    entry->mNotifyConsumed->setInt32("render", true);
Loading