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

Commit 2eee2bf9 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "codec2: Add SimpleC2Component"

parents 438e0eba 016aa4d0
Loading
Loading
Loading
Loading
+42 −0
Original line number Original line Diff line number Diff line
@@ -35,6 +35,48 @@ cc_library_shared {
    ldflags: ["-Wl,-Bsymbolic"],
    ldflags: ["-Wl,-Bsymbolic"],
}
}


cc_library_shared {
    name: "libstagefright_simple_c2component",

    tags: [
        "optional",
    ],

    srcs: ["SimpleC2Component.cpp"],

    include_dirs: [
        "frameworks/av/media/libstagefright/codec2/include",
    ],

    shared_libs: [
        "android.hardware.graphics.allocator@2.0",
        "android.hardware.graphics.mapper@2.0",
        "libhidlbase",
        "libion",
        "liblog",
        "libstagefright_codec2",
        "libstagefright_foundation",
	"libutils",
    ],

    static_libs: [
        "libstagefright_codec2_vndk",
    ],

    sanitize: {
        misc_undefined: [
            "unsigned-integer-overflow",
            "signed-integer-overflow",
        ],
        cfi: true,
        diag: {
            cfi: true,
        },
    },

    ldflags: ["-Wl,-Bsymbolic"],
}

subdirs = [
subdirs = [
    "tests",
    "tests",
    "vndk",
    "vndk",
+295 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_NDEBUG 0
#define LOG_TAG "SimpleC2Component"
#include <media/stagefright/foundation/ADebug.h>

#include <C2PlatformSupport.h>

#include <SimpleC2Component.h>

namespace android {

SimpleC2Component::SimpleC2Component(
        const std::shared_ptr<C2ComponentInterface> &intf)
    : mIntf(intf) {
}

c2_status_t SimpleC2Component::setListener_sm(const std::shared_ptr<C2Component::Listener> &listener) {
    Mutexed<ExecState>::Locked state(mExecState);
    if (state->mState == RUNNING) {
        return C2_BAD_STATE;
    }
    state->mListener = listener;
    return C2_OK;
}

c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
    {
        Mutexed<ExecState>::Locked state(mExecState);
        if (state->mState != RUNNING) {
            return C2_BAD_STATE;
        }
    }
    {
        Mutexed<WorkQueue>::Locked queue(mWorkQueue);
        while (!items->empty()) {
            queue->mQueue.push_back(std::move(items->front()));
            items->pop_front();
        }
        queue->mCondition.broadcast();
    }
    return C2_OK;
}

c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
    (void) items;
    return C2_OMITTED;
}

c2_status_t SimpleC2Component::flush_sm(
        flush_mode_t flushThrough, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
    (void) flushThrough;
    {
        Mutexed<ExecState>::Locked state(mExecState);
        if (state->mState != RUNNING) {
            return C2_BAD_STATE;
        }
    }
    {
        Mutexed<WorkQueue>::Locked queue(mWorkQueue);
        ++queue->mGeneration;
        while (!queue->mQueue.empty()) {
            flushedWork->push_back(std::move(queue->mQueue.front()));
            queue->mQueue.pop_front();
        }
    }
    {
        Mutexed<PendingWork>::Locked pending(mPendingWork);
        while (!pending->empty()) {
            flushedWork->push_back(std::move(pending->begin()->second));
            pending->erase(pending->begin());
        }
    }

    return onFlush_sm();
}

c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainThrough) {
    (void) drainThrough;
    {
        Mutexed<ExecState>::Locked state(mExecState);
        if (state->mState != RUNNING) {
            return C2_BAD_STATE;
        }
    }
    {
        Mutexed<WorkQueue>::Locked queue(mWorkQueue);
        if (!queue->mQueue.empty()) {
            const std::unique_ptr<C2Work> &work = queue->mQueue.back();
            work->input.flags = (C2BufferPack::flags_t)(work->input.flags | C2BufferPack::FLAG_END_OF_STREAM);
            return C2_OK;
        }
    }

    return onDrain_nb();
}

c2_status_t SimpleC2Component::start() {
    Mutexed<ExecState>::Locked state(mExecState);
    if (state->mState == RUNNING) {
        return C2_BAD_STATE;
    }
    bool needsInit = (state->mState == UNINITIALIZED);
    if (needsInit) {
        state.unlock();
        c2_status_t err = onInit();
        if (err != C2_OK) {
            return err;
        }
        state.lock();
    }
    if (!state->mThread.joinable()) {
        mExitRequested = false;
        state->mThread = std::thread(
                [](std::weak_ptr<SimpleC2Component> wp) {
                    while (true) {
                        std::shared_ptr<SimpleC2Component> thiz = wp.lock();
                        if (!thiz) {
                            return;
                        }
                        if (thiz->exitRequested()) {
                            return;
                        }
                        thiz->processQueue();
                    }
                },
                shared_from_this());
    }
    state->mState = RUNNING;
    return C2_OK;
}

c2_status_t SimpleC2Component::stop() {
    {
        Mutexed<ExecState>::Locked state(mExecState);
        if (state->mState != RUNNING) {
            return C2_BAD_STATE;
        }
        state->mState = STOPPED;
    }
    {
        Mutexed<WorkQueue>::Locked queue(mWorkQueue);
        queue->mQueue.clear();
    }
    {
        Mutexed<PendingWork>::Locked pending(mPendingWork);
        pending->clear();
    }
    c2_status_t err = onStop();
    if (err != C2_OK) {
        return err;
    }
    return C2_OK;
}

void SimpleC2Component::reset() {
    {
        Mutexed<ExecState>::Locked state(mExecState);
        state->mState = UNINITIALIZED;
    }
    {
        Mutexed<WorkQueue>::Locked queue(mWorkQueue);
        queue->mQueue.clear();
    }
    {
        Mutexed<PendingWork>::Locked pending(mPendingWork);
        pending->clear();
    }
    onReset();
}

void SimpleC2Component::release() {
    {
        Mutexed<ExecState>::Locked state(mExecState);
        mExitRequested = true;
        state->mThread.join();
    }
    onRelease();
}

std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
    return mIntf;
}

namespace {

std::vector<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
    std::vector<std::unique_ptr<C2Work>> ret;
    ret.push_back(std::move(work));
    return ret;
}

}  // namespace

void SimpleC2Component::finish(
        uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
    std::unique_ptr<C2Work> work;
    {
        Mutexed<PendingWork>::Locked pending(mPendingWork);
        if (pending->count(frameIndex) == 0) {
            return;
        }
        work = std::move(pending->at(frameIndex));
        pending->erase(frameIndex);
    }
    if (work) {
        fillWork(work);
        Mutexed<ExecState>::Locked state(mExecState);
        state->mListener->onWorkDone_nb(shared_from_this(), vec(work));
    }
}

void SimpleC2Component::processQueue() {
    std::unique_ptr<C2Work> work;
    uint64_t generation;
    {
        Mutexed<WorkQueue>::Locked queue(mWorkQueue);
        nsecs_t deadline = systemTime() + ms2ns(250);
        while (queue->mQueue.empty()) {
            status_t err = queue.waitForConditionRelative(
                    queue->mCondition, std::max(deadline - systemTime(), (nsecs_t)0));
            if (err == TIMED_OUT) {
                return;
            }
        }

        generation = queue->mGeneration;
        work = std::move(queue->mQueue.front());
        queue->mQueue.pop_front();
    }
    if (!work) {
        return;
    }

    // TODO: grab pool ID from intf
    if (!mOutputBlockPool) {
        c2_status_t err = GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, shared_from_this(), &mOutputBlockPool);
        if (err != C2_OK) {
            Mutexed<ExecState>::Locked state(mExecState);
            state->mListener->onError_nb(shared_from_this(), err);
            return;
        }
    }

    bool done = process(work, mOutputBlockPool);
    {
        Mutexed<WorkQueue>::Locked queue(mWorkQueue);
        if (queue->mGeneration != generation) {
            work->result = C2_NOT_FOUND;
            queue.unlock();
            {
                Mutexed<ExecState>::Locked state(mExecState);
                state->mListener->onWorkDone_nb(shared_from_this(), vec(work));
            }
            queue.lock();
            return;
        }
    }
    if (done) {
        Mutexed<ExecState>::Locked state(mExecState);
        state->mListener->onWorkDone_nb(shared_from_this(), vec(work));
    } else {
        std::unique_ptr<C2Work> unexpected;
        {
            Mutexed<PendingWork>::Locked pending(mPendingWork);
            uint64_t frameIndex = work->input.ordinal.frame_index;
            if (pending->count(frameIndex) != 0) {
                unexpected = std::move(pending->at(frameIndex));
                pending->erase(frameIndex);
            }
            (void) pending->insert({ frameIndex, std::move(work) });
        }
        if (unexpected) {
            unexpected->result = C2_CORRUPTED;
            Mutexed<ExecState>::Locked state(mExecState);
            state->mListener->onWorkDone_nb(shared_from_this(), vec(unexpected));
        }
    }
}

} // namespace android
+153 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SIMPLE_C2_COMPONENT_H_
#define SIMPLE_C2_COMPONENT_H_

#include <list>
#include <thread>
#include <unordered_map>

#include <C2Component.h>

#include <media/stagefright/foundation/Mutexed.h>

namespace android {

class SimpleC2Component
        : public C2Component, public std::enable_shared_from_this<SimpleC2Component> {
public:
    SimpleC2Component(
            const std::shared_ptr<C2ComponentInterface> &intf);
    virtual ~SimpleC2Component() = default;

    // C2Component
    virtual c2_status_t setListener_sm(const std::shared_ptr<C2Component::Listener> &listener) final;
    virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>> * const items) final;
    virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) final;
    virtual c2_status_t flush_sm(
            flush_mode_t flushThrough, std::list<std::unique_ptr<C2Work>>* const flushedWork) final;
    virtual c2_status_t drain_nb(drain_mode_t drainThrough) final;
    virtual c2_status_t start() final;
    virtual c2_status_t stop() final;
    virtual void reset() final;
    virtual void release() final;
    virtual std::shared_ptr<C2ComponentInterface> intf() final;

    // for thread
    inline bool exitRequested() { return mExitRequested; }
    void processQueue();

protected:
    /**
     * Initialize internal states of the component according to the config set
     * in the interface.
     *
     * This method is called during start(), but only at the first invocation or
     * after reset().
     */
    virtual c2_status_t onInit() = 0;

    /**
     * Stop the component.
     */
    virtual c2_status_t onStop() = 0;

    /**
     * Reset the component.
     */
    virtual void onReset() = 0;

    /**
     * Release the component.
     */
    virtual void onRelease() = 0;

    /**
     * Flush the component.
     */
    virtual c2_status_t onFlush_sm() = 0;

    /**
     * Drain the component.
     */
    virtual c2_status_t onDrain_nb() = 0;

    /**
     * Process the given work and finish pending work using finish().
     *
     * \param[in,out]   work    the work to process
     * \param[in]       pool    the pool to use for allocating output blocks.
     *
     * \retval true             |work| is done and ready for return to client
     * \retval false            more data is needed for the |work| to be done;
     *                          mark |work| as pending.
     */
    virtual bool process(
            const std::unique_ptr<C2Work> &work,
            std::shared_ptr<C2BlockPool> pool) = 0;

    // for derived classes
    /**
     * Finish pending work.
     *
     * This method will retrieve the pending work according to |frameIndex| and
     * feed the work into |fillWork| function. |fillWork| must be
     * "non-blocking". Once |fillWork| returns the filled work will be returned
     * to the client.
     *
     * \param[in]   frameIndex    the index of the pending work
     * \param[in]   fillWork      the function to fill the retrieved work.
     */
    void finish(uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork);

private:
    const std::shared_ptr<C2ComponentInterface> mIntf;
    std::atomic_bool mExitRequested;

    enum {
        UNINITIALIZED,
        STOPPED,
        RUNNING,
    };

    struct ExecState {
        ExecState() : mState(UNINITIALIZED) {}

        int mState;
        std::thread mThread;
        std::shared_ptr<C2Component::Listener> mListener;
    };
    Mutexed<ExecState> mExecState;

    struct WorkQueue {
        Condition mCondition;
        std::list<std::unique_ptr<C2Work>> mQueue;
        uint64_t mGeneration;
    };
    Mutexed<WorkQueue> mWorkQueue;

    typedef std::unordered_map<uint64_t, std::unique_ptr<C2Work>> PendingWork;
    Mutexed<PendingWork> mPendingWork;

    std::shared_ptr<C2BlockPool> mOutputBlockPool;

    SimpleC2Component() = delete;
};

}  // namespace android

#endif  // SIMPLE_C2_COMPONENT_H_
+0 −1
Original line number Original line Diff line number Diff line
@@ -15,7 +15,6 @@ cc_library_static {


    include_dirs: [
    include_dirs: [
        "frameworks/av/media/libstagefright/codec2/include",
        "frameworks/av/media/libstagefright/codec2/include",
        "frameworks/av/media/libstagefright/codec2/vndk/include",
        "frameworks/native/include/media/hardware",
        "frameworks/native/include/media/hardware",
    ],
    ],


+1 −0
Original line number Original line Diff line number Diff line
@@ -67,6 +67,7 @@ cc_library_shared {
        "libmedia",
        "libmedia",
        "libstagefright_codec2",
        "libstagefright_codec2",
        "libstagefright_foundation",
        "libstagefright_foundation",
        "libstagefright_simple_c2component",
        "libutils",
        "libutils",
    ],
    ],


Loading