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

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

Merge "Codec2: add C2PlatformComponentStore"

parents 5ebc890b ada89117
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -360,6 +360,7 @@ public:
        C2DomainKind domain;       ///< component domain (e.g. audio or video)
        C2ComponentKind type;      ///< component type (e.g. encoder, decoder or filter)
        C2StringLiteral mediaType; ///< media type supported by the component
        C2ComponentPriority priority; ///< priority used to determine component ordering

        /**
         * name alias(es) for backward compatibility.
@@ -569,7 +570,6 @@ public:
     */
    virtual std::shared_ptr<C2ComponentInterface> intf() = 0;

protected:
    virtual ~C2Component() = default;
};

@@ -724,11 +724,11 @@ public:
    /**
     * Returns the list of components supported by this component store.
     *
     * This method may be momentarily blocking, but MUST return within 5ms.
     * This method MUST return within 500ms.
     *
     * \retval vector of component information.
     */
    virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents_sm() const = 0;
    virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() = 0;

    // -------------------------------------- UTILITY METHODS --------------------------------------

+402 −5
Original line number Diff line number Diff line
@@ -20,12 +20,26 @@
#include <C2Component.h>
#include <C2PlatformSupport.h>

#define LOG_TAG "C2Store"
#define LOG_NDEBUG 0
#include <utils/Log.h>

#include <dlfcn.h>

#include <map>
#include <memory>
#include <mutex>

namespace android {

/**
 * The platform allocator store provides basic allocator-types for the framework based on ion and
 * gralloc. Allocators are not meant to be updatable.
 *
 * \todo Provide allocator based on ashmem
 * \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags
 * \todo Make this allocator store extendable
 */
class C2PlatformAllocatorStore : public C2AllocatorStore {
public:
    enum : id_t {
@@ -37,9 +51,11 @@ public:
        /* ionmapper */
    );

    virtual c2_status_t fetchAllocator(id_t id, std::shared_ptr<C2Allocator> *const allocator) override;
    virtual c2_status_t fetchAllocator(
            id_t id, std::shared_ptr<C2Allocator> *const allocator) override;

    virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb() const override {
    virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb()
            const override {
        return std::vector<std::shared_ptr<const C2Allocator::Traits>>(); /// \todo
    }

@@ -48,10 +64,10 @@ public:
    }

private:
    // returns a shared-singleton ion allocator
    /// returns a shared-singleton ion allocator
    std::shared_ptr<C2Allocator> fetchIonAllocator();

    // returns a shared-singleton gralloc allocator
    /// returns a shared-singleton gralloc allocator
    std::shared_ptr<C2Allocator> fetchGrallocAllocator();
};

@@ -141,4 +157,385 @@ c2_status_t GetCodec2BlockPool(
    return res;
}

class C2PlatformComponentStore : public C2ComponentStore {
public:
    virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override;
    virtual C2String getName() const override;
    virtual c2_status_t querySupportedValues_nb(
            std::vector<C2FieldSupportedValuesQuery> &fields) const override;
    virtual c2_status_t querySupportedParams_nb(
            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const override;
    virtual c2_status_t query_sm(
            const std::vector<C2Param *const> &stackParams,
            const std::vector<C2Param::Index> &heapParamIndices,
            std::vector<std::unique_ptr<C2Param>> *const heapParams) const override;
    virtual c2_status_t createInterface(
            C2String name, std::shared_ptr<C2ComponentInterface> *const interface) override;
    virtual c2_status_t createComponent(
            C2String name, std::shared_ptr<C2Component> *const component) override;
    virtual c2_status_t copyBuffer(
            std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) override;
    virtual c2_status_t config_sm(
            const std::vector<C2Param *const> &params,
            std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;
    virtual c2_status_t commit_sm(
            const std::vector<C2Param *const> &params,
            std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;

    C2PlatformComponentStore();

    virtual ~C2PlatformComponentStore() override = default;

private:

    /**
     * An object encapsulating a loaded component module.
     *
     * \todo provide a way to add traits to known components here to avoid loading the .so-s
     * for listComponents
     */
    struct ComponentModule : public C2ComponentFactory,
            public std::enable_shared_from_this<ComponentModule> {
        virtual c2_status_t createComponent(
                c2_node_id_t id, std::shared_ptr<C2Component> *component,
                ComponentDeleter deleter = std::default_delete<C2Component>()) override;
        virtual c2_status_t createInterface(
                c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
                InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) override;

        /**
         * \returns the traits of the component in this module.
         */
        std::shared_ptr<const C2Component::Traits> getTraits();

        /**
         * Creates an uninitialized component module.
         *
         * \note Only used by ComponentLoader.
         */
        ComponentModule() : mInit(C2_NO_INIT) {}

        /**
         * Initializes a component module with a given library path. Must be called exactly once.
         *
         * \note Only used by ComponentLoader.
         *
         * \param libPath[in] library path (or name)
         *
         * \retval C2_OK        the component module has been successfully loaded
         * \retval C2_NO_MEMORY not enough memory to loading the component module
         * \retval C2_NOT_FOUND could not locate the component module
         * \retval C2_CORRUPTED the component module could not be loaded (unexpected)
         * \retval C2_REFUSED   permission denied to load the component module (unexpected)
         * \retval C2_TIMED_OUT could not load the module within the time limit (unexpected)
         */
        c2_status_t init(std::string libPath);

        virtual ~ComponentModule() override;

    protected:
        std::recursive_mutex mLock; ///< lock protecting mTraits
        std::shared_ptr<C2Component::Traits> mTraits; ///< cached component traits

        c2_status_t mInit; ///< initialization result

        void *mLibHandle; ///< loaded library handle
        C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function
        C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function
        C2ComponentFactory *mComponentFactory; ///< loaded/created component factory
    };

    /**
     * An object encapsulating a loadable component module.
     *
     * \todo make this also work for enumerations
     */
    struct ComponentLoader {
        /**
         * Load the component module.
         *
         * This method simply returns the component module if it is already currently loaded, or
         * attempts to load it if it is not.
         *
         * \param module[out] pointer to the shared pointer where the loaded module shall be stored.
         *                    This will be nullptr on error.
         *
         * \retval C2_OK        the component module has been successfully loaded
         * \retval C2_NO_MEMORY not enough memory to loading the component module
         * \retval C2_NOT_FOUND could not locate the component module
         * \retval C2_CORRUPTED the component module could not be loaded
         * \retval C2_REFUSED   permission denied to load the component module
         */
        c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
            c2_status_t res = C2_OK;
            std::lock_guard<std::mutex> lock(mMutex);
            std::shared_ptr<ComponentModule> localModule = mModule.lock();
            if (localModule == nullptr) {
                localModule = std::make_shared<ComponentModule>();
                res = localModule->init(mLibPath);
                if (res == C2_OK) {
                    mModule = localModule;
                }
            }
            *module = localModule;
            return res;
        }

        /**
         * Creates a component loader for a specific library path (or name).
         */
        ComponentLoader(std::string libPath)
            : mLibPath(libPath) {}

    private:
        std::mutex mMutex; ///< mutex guarding the module
        std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
        std::string mLibPath; ///< library path (or name)
    };

    /**
     * Retrieves the component loader for a component.
     *
     * \return a non-ref-holding pointer to the component loader.
     *
     * \retval C2_OK        the component loader has been successfully retrieved
     * \retval C2_NO_MEMORY not enough memory to locate the component loader
     * \retval C2_NOT_FOUND could not locate the component to be loaded
     * \retval C2_CORRUPTED the component loader could not be identified due to some modules being
     *                      corrupted (this can happen if the name does not refer to an already
     *                      identified component but some components could not be loaded due to
     *                      bad library)
     * \retval C2_REFUSED   permission denied to find the component loader for the named component
     *                      (this can happen if the name does not refer to an already identified
     *                      component but some components could not be loaded due to lack of
     *                      permissions)
     */
    c2_status_t findComponent(C2String name, ComponentLoader **loader);

    std::map<C2String, ComponentLoader> mComponents; ///< list of components
};

c2_status_t C2PlatformComponentStore::ComponentModule::init(std::string libPath) {
    ALOGV("in %s", __func__);
    ALOGV("loading dll");
    mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
    if (mLibHandle == nullptr) {
        // could be access/symbol or simply not being there
        ALOGD("could not dlopen %s: %s", libPath.c_str(), dlerror());
        mInit = C2_CORRUPTED;
    } else {
        createFactory =
            (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
        destroyFactory =
            (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");

        mComponentFactory = createFactory();
        if (mComponentFactory == nullptr) {
            ALOGD("could not create factory in %s", libPath.c_str());
            mInit = C2_NO_MEMORY;
        } else {
            mInit = C2_OK;
        }
    }
    return mInit;
}

C2PlatformComponentStore::ComponentModule::~ComponentModule() {
    ALOGV("in %s", __func__);
    if (destroyFactory && mComponentFactory) {
        destroyFactory(mComponentFactory);
    }
    if (mLibHandle) {
        ALOGV("unloading dll");
        dlclose(mLibHandle);
    }
}

c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
        c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
        std::function<void(::android::C2ComponentInterface*)> deleter) {
    interface->reset();
    if (mInit != C2_OK) {
        return mInit;
    }
    std::shared_ptr<ComponentModule> module = shared_from_this();
    c2_status_t res = mComponentFactory->createInterface(
            id, interface, [module, deleter](C2ComponentInterface *p) mutable {
                // capture module so that we ensure we still have it while deleting interface
                deleter(p); // delete interface first
                module.reset(); // remove module ref (not technically needed)
    });
    return res;
}

c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
        c2_node_id_t id, std::shared_ptr<C2Component> *component,
        std::function<void(::android::C2Component*)> deleter) {
    component->reset();
    if (mInit != C2_OK) {
        return mInit;
    }
    std::shared_ptr<ComponentModule> module = shared_from_this();
    c2_status_t res = mComponentFactory->createComponent(
            id, component, [module, deleter](C2Component *p) mutable {
                // capture module so that we ensure we still have it while deleting component
                deleter(p); // delete component first
                module.reset(); // remove module ref (not technically needed)
    });
    return res;
}

std::shared_ptr<const C2Component::Traits> C2PlatformComponentStore::ComponentModule::getTraits() {
    std::unique_lock<std::recursive_mutex> lock(mLock);
    if (!mTraits) {
        std::shared_ptr<C2ComponentInterface> intf;
        c2_status_t res = createInterface(0, &intf);
        if (res != C2_OK) {
            return nullptr;
        }

        std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
        if (traits) {
            // traits->name = intf->getName();
        }

        mTraits = traits;
    }
    return mTraits;
}

C2PlatformComponentStore::C2PlatformComponentStore() {
    // TODO: move this also into a .so so it can be updated
    mComponents.emplace("c2.google.avc.decoder", "libstagefright_soft_c2avcdec.so");
}

c2_status_t C2PlatformComponentStore::copyBuffer(
        std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) {
    (void)src;
    (void)dst;
    return C2_OMITTED;
}

c2_status_t C2PlatformComponentStore::query_sm(
        const std::vector<C2Param *const> &stackParams,
        const std::vector<C2Param::Index> &heapParamIndices,
        std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
    // there are no supported configs
    (void)heapParams;
    return stackParams.empty() && heapParamIndices.empty() ? C2_OK : C2_BAD_INDEX;
}

c2_status_t C2PlatformComponentStore::config_sm(
        const std::vector<C2Param *const> &params,
        std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
    // there are no supported configs
    (void)failures;
    return params.empty() ? C2_OK : C2_BAD_INDEX;
}

c2_status_t C2PlatformComponentStore::commit_sm(
        const std::vector<C2Param *const> &params,
        std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
    // there are no supported configs
    (void)failures;
    return params.empty() ? C2_OK : C2_BAD_INDEX;
}

std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
    // This method SHALL return within 500ms.
    std::vector<std::shared_ptr<const C2Component::Traits>> list;
    for (auto &it : mComponents) {
        ComponentLoader &loader = it.second;
        std::shared_ptr<ComponentModule> module;
        c2_status_t res = loader.fetchModule(&module);
        if (res == C2_OK) {
            std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
            if (traits) {
                list.push_back(traits);
            }
        }
    }
    return list;
}

c2_status_t C2PlatformComponentStore::findComponent(C2String name, ComponentLoader **loader) {
    *loader = nullptr;
    auto pos = mComponents.find(name);
    // TODO: check aliases
    if (pos == mComponents.end()) {
        return C2_NOT_FOUND;
    }
    *loader = &pos->second;
    return C2_OK;
}

c2_status_t C2PlatformComponentStore::createComponent(
        C2String name, std::shared_ptr<C2Component> *const component) {
    // This method SHALL return within 100ms.
    component->reset();
    ComponentLoader *loader;
    c2_status_t res = findComponent(name, &loader);
    if (res == C2_OK) {
        std::shared_ptr<ComponentModule> module;
        res = loader->fetchModule(&module);
        if (res == C2_OK) {
            // TODO: get a unique node ID
            res = module->createComponent(0, component);
        }
    }
    return res;
}

c2_status_t C2PlatformComponentStore::createInterface(
        C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
    // This method SHALL return within 100ms.
    interface->reset();
    ComponentLoader *loader;
    c2_status_t res = findComponent(name, &loader);
    if (res == C2_OK) {
        std::shared_ptr<ComponentModule> module;
        res = loader->fetchModule(&module);
        if (res == C2_OK) {
            // TODO: get a unique node ID
            res = module->createInterface(0, interface);
        }
    }
    return res;
}

c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
        std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
    // there are no supported config params
    (void)params;
    return C2_OK;
}

c2_status_t C2PlatformComponentStore::querySupportedValues_nb(
        std::vector<C2FieldSupportedValuesQuery> &fields) const {
    // there are no supported config params
    return fields.empty() ? C2_OK : C2_BAD_INDEX;
}

C2String C2PlatformComponentStore::getName() const {
    return "android.componentStore.platform";
}

std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
    // TODO
    return nullptr;
}

std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
    static std::mutex mutex;
    static std::weak_ptr<C2ComponentStore> platformStore;
    std::lock_guard<std::mutex> lock(mutex);
    std::shared_ptr<C2ComponentStore> store = platformStore.lock();
    if (store == nullptr) {
        store = std::make_shared<C2PlatformComponentStore>();
        platformStore = store;
    }
    return store;
}

} // namespace android
+20 −4
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include <C2Component.h>

#include <functional>
#include <memory>

namespace android {
@@ -64,14 +65,17 @@ c2_status_t GetCodec2BlockPool(
 */
class C2ComponentFactory {
public:
    typedef std::function<void(::android::C2Component*)> ComponentDeleter;
    typedef std::function<void(::android::C2ComponentInterface*)> InterfaceDeleter;

    /**
     * Creates a component.
     *
     * This method SHALL return within 100ms.
     *
     * \param id        component ID for the created component
     * \param component shared pointer where the created component is stored. Cleared on
     *                  failure and updated on success.
     * \param id        component ID for the created component
     *
     * \retval C2_OK        the component was created successfully
     * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
@@ -80,16 +84,17 @@ public:
     * \retval C2_NO_MEMORY not enough memory to create the component
     */
    virtual c2_status_t createComponent(
            std::shared_ptr<C2Component>* const component, c2_node_id_t id) = 0;
            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
            ComponentDeleter deleter = std::default_delete<C2Component>()) = 0;

    /**
     * Creates a component interface.
     *
     * This method SHALL return within 100ms.
     *
     * \param id        component interface ID for the created interface
     * \param interface shared pointer where the created interface is stored. Cleared on
     *                  failure and updated on success.
     * \param id        component interface ID for the created interface
     *
     * \retval C2_OK        the component interface was created successfully
     * \retval C2_TIMED_OUT could not create the component interface within the time limit
@@ -100,11 +105,22 @@ public:
     * \retval C2_NO_MEMORY not enough memory to create the component interface
     */
    virtual c2_status_t createInterface(
            std::shared_ptr<C2ComponentInterface>* const interface, c2_node_id_t id) = 0;
            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
            InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) = 0;

    virtual ~C2ComponentFactory() = default;

    typedef ::android::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
    typedef void (*DestroyCodec2FactoryFunc)(::android::C2ComponentFactory*);
};

/**
 * Returns the platform component store.
 * \retval nullptr if the platform component store could not be obtained
 */
std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore();


} // namespace android

#endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
+16 −5
Original line number Diff line number Diff line
@@ -261,7 +261,7 @@ C2SoftAvcDecIntf::C2SoftAvcDecIntf(const char *name, c2_node_id_t id)
      mFrameRate(0u, 0),
      mBlocksPerSecond(0u, 0),
      mParamReflector(new ParamReflector) {

    ALOGV("in %s", __func__);
    mInputPortMime = C2PortMimeConfig::input::alloc_unique(strlen(CODEC_MIME_TYPE) + 1);
    strcpy(mInputPortMime->m.mValue, CODEC_MIME_TYPE);
    mOutputPortMime = C2PortMimeConfig::output::alloc_unique(strlen(MEDIA_MIMETYPE_VIDEO_RAW) + 1);
@@ -430,6 +430,10 @@ C2SoftAvcDecIntf::C2SoftAvcDecIntf(const char *name, c2_node_id_t id)
            false, "_output_block_pools", mOutputBlockPools.get()));
}

C2SoftAvcDecIntf::~C2SoftAvcDecIntf() {
    ALOGV("in %s", __func__);
}

C2String C2SoftAvcDecIntf::getName() const {
    return mName;
}
@@ -653,6 +657,7 @@ C2SoftAvcDec::C2SoftAvcDec(
      mWidth(320),
      mHeight(240),
      mInputOffset(0) {
    ALOGV("in %s", __func__);
    GETTIME(&mTimeStart, NULL);

    // If input dump is enabled, then open create an empty file
@@ -661,6 +666,7 @@ C2SoftAvcDec::C2SoftAvcDec(
}

C2SoftAvcDec::~C2SoftAvcDec() {
    ALOGV("in %s", __func__);
    CHECK_EQ(deInitDecoder(), (status_t)OK);
}

@@ -1505,14 +1511,17 @@ status_t C2SoftAvcDec::handleColorAspectsChange() {
class C2SoftAvcDecFactory : public C2ComponentFactory {
public:
    virtual c2_status_t createComponent(
            std::shared_ptr<C2Component>* const component, c2_node_id_t id) override {
        *component = std::make_shared<C2SoftAvcDec>("avc", id);
            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
            std::function<void(::android::C2Component*)> deleter) override {
        *component = std::shared_ptr<C2Component>(new C2SoftAvcDec("avc", id), deleter);
        return C2_OK;
    }

    virtual c2_status_t createInterface(
            std::shared_ptr<C2ComponentInterface>* const interface, c2_node_id_t id) override {
        *interface = std::make_shared<C2SoftAvcDecIntf>("avc", id);
            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
            std::function<void(::android::C2ComponentInterface*)> deleter) override {
        *interface =
            std::shared_ptr<C2ComponentInterface>(new C2SoftAvcDecIntf("avc", id), deleter);
        return C2_OK;
    }

@@ -1522,9 +1531,11 @@ public:
}  // namespace android

extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
    ALOGV("in %s", __func__);
    return new ::android::C2SoftAvcDecFactory();
}

extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
    ALOGV("in %s", __func__);
    delete factory;
}
+1 −1
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ public:
    };

    C2SoftAvcDecIntf(const char *name, c2_node_id_t id);
    virtual ~C2SoftAvcDecIntf() = default;
    virtual ~C2SoftAvcDecIntf() override;

    // From C2ComponentInterface
    virtual C2String getName() const override;
Loading