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

Commit d54118ff authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Reland CCodecBufferChannel: Process output format when registering...

Merge "Reland CCodecBufferChannel: Process output format when registering buffer" into rvc-dev am: 2afc10be

Change-Id: I89f3fadde24bec2b1a7db08ea166d82e17a6699a
parents 189d92ed 2afc10be
Loading
Loading
Loading
Loading
+101 −193
Original line number Diff line number Diff line
@@ -128,97 +128,6 @@ void CCodecBufferChannel::QueueSync::stop() {
    count->value = -1;
}

// CCodecBufferChannel::ReorderStash

CCodecBufferChannel::ReorderStash::ReorderStash() {
    clear();
}

void CCodecBufferChannel::ReorderStash::clear() {
    mPending.clear();
    mStash.clear();
    mDepth = 0;
    mKey = C2Config::ORDINAL;
}

void CCodecBufferChannel::ReorderStash::flush() {
    mPending.clear();
    mStash.clear();
}

void CCodecBufferChannel::ReorderStash::setDepth(uint32_t depth) {
    mPending.splice(mPending.end(), mStash);
    mDepth = depth;
}

void CCodecBufferChannel::ReorderStash::setKey(C2Config::ordinal_key_t key) {
    mPending.splice(mPending.end(), mStash);
    mKey = key;
}

bool CCodecBufferChannel::ReorderStash::pop(Entry *entry) {
    if (mPending.empty()) {
        return false;
    }
    entry->buffer     = mPending.front().buffer;
    entry->timestamp  = mPending.front().timestamp;
    entry->flags      = mPending.front().flags;
    entry->ordinal    = mPending.front().ordinal;
    mPending.pop_front();
    return true;
}

void CCodecBufferChannel::ReorderStash::emplace(
        const std::shared_ptr<C2Buffer> &buffer,
        int64_t timestamp,
        int32_t flags,
        const C2WorkOrdinalStruct &ordinal) {
    bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
    if (!buffer && eos) {
        // TRICKY: we may be violating ordering of the stash here. Because we
        // don't expect any more emplace() calls after this, the ordering should
        // not matter.
        mStash.emplace_back(buffer, timestamp, flags, ordinal);
    } else {
        flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
        auto it = mStash.begin();
        for (; it != mStash.end(); ++it) {
            if (less(ordinal, it->ordinal)) {
                break;
            }
        }
        mStash.emplace(it, buffer, timestamp, flags, ordinal);
        if (eos) {
            mStash.back().flags = mStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
        }
    }
    while (!mStash.empty() && mStash.size() > mDepth) {
        mPending.push_back(mStash.front());
        mStash.pop_front();
    }
}

void CCodecBufferChannel::ReorderStash::defer(
        const CCodecBufferChannel::ReorderStash::Entry &entry) {
    mPending.push_front(entry);
}

bool CCodecBufferChannel::ReorderStash::hasPending() const {
    return !mPending.empty();
}

bool CCodecBufferChannel::ReorderStash::less(
        const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) {
    switch (mKey) {
        case C2Config::ORDINAL:   return o1.frameIndex < o2.frameIndex;
        case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
        case C2Config::CUSTOM:    return o1.customOrdinal < o2.customOrdinal;
        default:
            ALOGD("Unrecognized key; default to timestamp");
            return o1.frameIndex < o2.frameIndex;
    }
}

// Input

CCodecBufferChannel::Input::Input() : extraBuffers("extra") {}
@@ -708,7 +617,7 @@ void CCodecBufferChannel::feedInputBufferIfAvailable() {

void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
    if (mInputMetEos ||
           mReorderStash.lock()->hasPending() ||
           mOutput.lock()->buffers->hasPending() ||
           mPipelineWatcher.lock()->pipelineFull()) {
        return;
    } else {
@@ -989,17 +898,6 @@ status_t CCodecBufferChannel::start(
        return UNKNOWN_ERROR;
    }

    {
        Mutexed<ReorderStash>::Locked reorder(mReorderStash);
        reorder->clear();
        if (reorderDepth) {
            reorder->setDepth(reorderDepth.value);
        }
        if (reorderKey) {
            reorder->setKey(reorderKey.value);
        }
    }

    uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
    uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
    uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
@@ -1268,6 +1166,13 @@ status_t CCodecBufferChannel::start(
        }
        output->buffers->setFormat(outputFormat);

        output->buffers->clearStash();
        if (reorderDepth) {
            output->buffers->setReorderDepth(reorderDepth.value);
        }
        if (reorderKey) {
            output->buffers->setReorderKey(reorderKey.value);
        }

        // Try to set output surface to created block pool if given.
        if (outputSurface) {
@@ -1464,9 +1369,9 @@ void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushe
        Mutexed<Output>::Locked output(mOutput);
        if (output->buffers) {
            output->buffers->flush(flushedWork);
            output->buffers->flushStash();
        }
    }
    mReorderStash.lock()->flush();
    mPipelineWatcher.lock()->flush();
}

@@ -1507,45 +1412,36 @@ bool CCodecBufferChannel::handleWork(
        if (!output->buffers) {
            return false;
        }
        if (outputFormat != nullptr) {
            ALOGD("[%s] onWorkDone: output format changed to %s",
                    mName, outputFormat->debugString().c_str());
            output->buffers->setFormat(outputFormat);

            AString mediaType;
            if (outputFormat->findString(KEY_MIME, &mediaType)
                    && mediaType == MIMETYPE_AUDIO_RAW) {
                int32_t channelCount;
                int32_t sampleRate;
                if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
                        && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
                    output->buffers->updateSkipCutBuffer(sampleRate, channelCount);
                }
            }
    }

    // Whether the output buffer should be reported to the client or not.
    bool notifyClient = false;

    if (work->result == C2_OK){
        notifyClient = true;
    } else if (work->result == C2_NOT_FOUND) {
        ALOGD("[%s] flushed work; ignored.", mName);
    } else {
        // C2_OK and C2_NOT_FOUND are the only results that we accept for processing
        // the config update.
        ALOGD("[%s] work failed to complete: %d", mName, work->result);
        mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
        return false;
    }

    if ((work->input.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) {
    if ((work->input.ordinal.frameIndex -
            mFirstValidFrameIndex.load()).peek() < 0) {
        // Discard frames from previous generation.
        ALOGD("[%s] Discard frames from previous generation.", mName);
        return false;
        notifyClient = false;
    }

    if (mInputSurface == nullptr && (work->worklets.size() != 1u
            || !work->worklets.front()
            || !(work->worklets.front()->output.flags & C2FrameData::FLAG_INCOMPLETE))) {
        mPipelineWatcher.lock()->onWorkDone(work->input.ordinal.frameIndex.peeku());
    }

    if (work->result == C2_NOT_FOUND) {
        ALOGD("[%s] flushed work; ignored.", mName);
        return true;
    }

    if (work->result != C2_OK) {
        ALOGD("[%s] work failed to complete: %d", mName, work->result);
        mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
        return false;
            || !(work->worklets.front()->output.flags &
                 C2FrameData::FLAG_INCOMPLETE))) {
        mPipelineWatcher.lock()->onWorkDone(
                work->input.ordinal.frameIndex.peeku());
    }

    // NOTE: MediaCodec usage supposedly have only one worklet
@@ -1581,8 +1477,10 @@ bool CCodecBufferChannel::handleWork(
            case C2PortReorderBufferDepthTuning::CORE_INDEX: {
                C2PortReorderBufferDepthTuning::output reorderDepth;
                if (reorderDepth.updateFrom(*param)) {
                    bool secure = mComponent->getName().find(".secure") != std::string::npos;
                    mReorderStash.lock()->setDepth(reorderDepth.value);
                    bool secure = mComponent->getName().find(".secure") !=
                                  std::string::npos;
                    mOutput.lock()->buffers->setReorderDepth(
                            reorderDepth.value);
                    ALOGV("[%s] onWorkDone: updated reorder depth to %u",
                          mName, reorderDepth.value);
                    size_t numOutputSlots = mOutput.lock()->numSlots;
@@ -1594,17 +1492,19 @@ bool CCodecBufferChannel::handleWork(
                        output->maxDequeueBuffers += numInputSlots;
                    }
                    if (output->surface) {
                        output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
                        output->surface->setMaxDequeuedBufferCount(
                                output->maxDequeueBuffers);
                    }
                } else {
                    ALOGD("[%s] onWorkDone: failed to read reorder depth", mName);
                    ALOGD("[%s] onWorkDone: failed to read reorder depth",
                          mName);
                }
                break;
            }
            case C2PortReorderKeySetting::CORE_INDEX: {
                C2PortReorderKeySetting::output reorderKey;
                if (reorderKey.updateFrom(*param)) {
                    mReorderStash.lock()->setKey(reorderKey.value);
                    mOutput.lock()->buffers->setReorderKey(reorderKey.value);
                    ALOGV("[%s] onWorkDone: updated reorder key to %u",
                          mName, reorderKey.value);
                } else {
@@ -1619,7 +1519,8 @@ bool CCodecBufferChannel::handleWork(
                        ALOGV("[%s] onWorkDone: updating pipeline delay %u",
                              mName, pipelineDelay.value);
                        newPipelineDelay = pipelineDelay.value;
                        (void)mPipelineWatcher.lock()->pipelineDelay(pipelineDelay.value);
                        (void)mPipelineWatcher.lock()->pipelineDelay(
                                pipelineDelay.value);
                    }
                }
                if (param->forInput()) {
@@ -1628,7 +1529,8 @@ bool CCodecBufferChannel::handleWork(
                        ALOGV("[%s] onWorkDone: updating input delay %u",
                              mName, inputDelay.value);
                        newInputDelay = inputDelay.value;
                        (void)mPipelineWatcher.lock()->inputDelay(inputDelay.value);
                        (void)mPipelineWatcher.lock()->inputDelay(
                                inputDelay.value);
                    }
                }
                if (param->forOutput()) {
@@ -1636,8 +1538,10 @@ bool CCodecBufferChannel::handleWork(
                    if (outputDelay.updateFrom(*param)) {
                        ALOGV("[%s] onWorkDone: updating output delay %u",
                              mName, outputDelay.value);
                        bool secure = mComponent->getName().find(".secure") != std::string::npos;
                        (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
                        bool secure = mComponent->getName().find(".secure") !=
                                      std::string::npos;
                        (void)mPipelineWatcher.lock()->outputDelay(
                                outputDelay.value);

                        bool outputBuffersChanged = false;
                        size_t numOutputSlots = 0;
@@ -1648,7 +1552,8 @@ bool CCodecBufferChannel::handleWork(
                                return false;
                            }
                            output->outputDelay = outputDelay.value;
                            numOutputSlots = outputDelay.value + kSmoothnessFactor;
                            numOutputSlots = outputDelay.value +
                                             kSmoothnessFactor;
                            if (output->numSlots < numOutputSlots) {
                                output->numSlots = numOutputSlots;
                                if (output->buffers->isArrayMode()) {
@@ -1667,7 +1572,7 @@ bool CCodecBufferChannel::handleWork(
                            mCCodecCallback->onOutputBuffersChanged();
                        }

                        uint32_t depth = mReorderStash.lock()->depth();
                        uint32_t depth = mOutput.lock()->buffers->getReorderDepth();
                        Mutexed<OutputSurface>::Locked output(mOutputSurface);
                        output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth;
                        if (!secure) {
@@ -1711,9 +1616,6 @@ bool CCodecBufferChannel::handleWork(
        ALOGV("[%s] onWorkDone: output EOS", mName);
    }

    sp<MediaCodecBuffer> outBuffer;
    size_t index;

    // WORKAROUND: adjust output timestamp based on client input timestamp and codec
    // input timestamp. Codec output timestamp (in the timestamp field) shall correspond to
    // the codec input timestamp, but client output timestamp should (reported in timeUs)
@@ -1734,8 +1636,18 @@ bool CCodecBufferChannel::handleWork(
          worklet->output.ordinal.timestamp.peekll(),
          timestamp.peekll());

    // csd cannot be re-ordered and will always arrive first.
    if (initData != nullptr) {
        Mutexed<Output>::Locked output(mOutput);
        if (output->buffers && outputFormat) {
            output->buffers->updateSkipCutBuffer(outputFormat);
            output->buffers->setFormat(outputFormat);
        }
        if (!notifyClient) {
            return false;
        }
        size_t index;
        sp<MediaCodecBuffer> outBuffer;
        if (output->buffers && output->buffers->registerCsd(initData, &index, &outBuffer) == OK) {
            outBuffer->meta()->setInt64("timeUs", timestamp.peek());
            outBuffer->meta()->setInt32("flags", MediaCodec::BUFFER_FLAG_CODECCONFIG);
@@ -1751,10 +1663,10 @@ bool CCodecBufferChannel::handleWork(
        }
    }

    if (!buffer && !flags) {
    if (notifyClient && !buffer && !flags) {
        ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
              mName, work->input.ordinal.frameIndex.peekull());
        return true;
        notifyClient = false;
    }

    if (buffer) {
@@ -1773,66 +1685,62 @@ bool CCodecBufferChannel::handleWork(
    }

    {
        Mutexed<ReorderStash>::Locked reorder(mReorderStash);
        reorder->emplace(buffer, timestamp.peek(), flags, worklet->output.ordinal);
        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
            // Flush reorder stash
            reorder->setDepth(0);
        }
        Mutexed<Output>::Locked output(mOutput);
        output->buffers->pushToStash(
                buffer,
                notifyClient,
                timestamp.peek(),
                flags,
                outputFormat,
                worklet->output.ordinal);
    }
    sendOutputBuffers();
    return true;
}

void CCodecBufferChannel::sendOutputBuffers() {
    ReorderStash::Entry entry;
    sp<MediaCodecBuffer> outBuffer;
    OutputBuffers::BufferAction action;
    size_t index;
    sp<MediaCodecBuffer> outBuffer;
    std::shared_ptr<C2Buffer> c2Buffer;

    while (true) {
        Mutexed<ReorderStash>::Locked reorder(mReorderStash);
        if (!reorder->hasPending()) {
            break;
        }
        if (!reorder->pop(&entry)) {
            break;
        }

        Mutexed<Output>::Locked output(mOutput);
        if (!output->buffers) {
            return;
        }
        status_t err = output->buffers->registerBuffer(entry.buffer, &index, &outBuffer);
        if (err != OK) {
            bool outputBuffersChanged = false;
            if (err != WOULD_BLOCK) {
        action = output->buffers->popFromStashAndRegister(
                &c2Buffer, &index, &outBuffer);
        switch (action) {
        case OutputBuffers::SKIP:
            return;
        case OutputBuffers::DISCARD:
            break;
        case OutputBuffers::NOTIFY_CLIENT:
            output.unlock();
            mCallback->onOutputBufferAvailable(index, outBuffer);
            break;
        case OutputBuffers::REALLOCATE:
            if (!output->buffers->isArrayMode()) {
                    output->buffers = output->buffers->toArrayMode(output->numSlots);
                }
                OutputBuffersArray *array = (OutputBuffersArray *)output->buffers.get();
                array->realloc(entry.buffer);
                outputBuffersChanged = true;
                output->buffers =
                    output->buffers->toArrayMode(output->numSlots);
            }
            ALOGV("[%s] sendOutputBuffers: unable to register output buffer", mName);
            reorder->defer(entry);

            static_cast<OutputBuffersArray*>(output->buffers.get())->
                    realloc(c2Buffer);
            output.unlock();
            reorder.unlock();

            if (outputBuffersChanged) {
            mCCodecCallback->onOutputBuffersChanged();
            }
            return;
        case OutputBuffers::RETRY:
            ALOGV("[%s] sendOutputBuffers: unable to register output buffer",
                  mName);
            return;
        default:
            LOG_ALWAYS_FATAL("[%s] sendOutputBuffers: "
                    "corrupted BufferAction value (%d) "
                    "returned from popFromStashAndRegister.",
                    mName, int(action));
            return;
        }
        output.unlock();
        reorder.unlock();

        outBuffer->meta()->setInt64("timeUs", entry.timestamp);
        outBuffer->meta()->setInt32("flags", entry.flags);
        ALOGV("[%s] sendOutputBuffers: out buffer index = %zu [%p] => %p + %zu (%lld)",
                mName, index, outBuffer.get(), outBuffer->data(), outBuffer->size(),
                (long long)entry.timestamp);
        mCallback->onOutputBufferAvailable(index, outBuffer);
    }
}

+0 −42
Original line number Diff line number Diff line
@@ -306,48 +306,6 @@ private:

    Mutexed<PipelineWatcher> mPipelineWatcher;

    class ReorderStash {
    public:
        struct Entry {
            inline Entry() : buffer(nullptr), timestamp(0), flags(0), ordinal({0, 0, 0}) {}
            inline Entry(
                    const std::shared_ptr<C2Buffer> &b,
                    int64_t t,
                    int32_t f,
                    const C2WorkOrdinalStruct &o)
                : buffer(b), timestamp(t), flags(f), ordinal(o) {}
            std::shared_ptr<C2Buffer> buffer;
            int64_t timestamp;
            int32_t flags;
            C2WorkOrdinalStruct ordinal;
        };

        ReorderStash();

        void clear();
        void flush();
        void setDepth(uint32_t depth);
        void setKey(C2Config::ordinal_key_t key);
        bool pop(Entry *entry);
        void emplace(
                const std::shared_ptr<C2Buffer> &buffer,
                int64_t timestamp,
                int32_t flags,
                const C2WorkOrdinalStruct &ordinal);
        void defer(const Entry &entry);
        bool hasPending() const;
        uint32_t depth() const { return mDepth; }

    private:
        std::list<Entry> mPending;
        std::list<Entry> mStash;
        uint32_t mDepth;
        C2Config::ordinal_key_t mKey;

        bool less(const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2);
    };
    Mutexed<ReorderStash> mReorderStash;

    std::atomic_bool mInputMetEos;
    std::once_flag mRenderWarningFlag;

+200 −8

File changed.

Preview size limit exceeded, changes collapsed.

+245 −11

File changed.

Preview size limit exceeded, changes collapsed.