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

Commit c90093cd authored by Wonsik Kim's avatar Wonsik Kim Committed by Gerrit Code Review
Browse files

Merge "Revert^4 "Codec2Client: add support to ApexCodec"" into main

parents 0fe0350b 935d4de6
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ cc_library {
    name: "libcodec2_client",

    srcs: [
        "ApexCodecsLazy.cpp",
        "GraphicBufferAllocator.cpp",
        "GraphicsTracker.cpp",
        "client.cpp",
@@ -41,17 +42,18 @@ cc_library {
    cpp_std: "gnu++20",

    header_libs: [
        "libapexcodecs-header",
        "libcodec2_internal", // private
    ],

    shared_libs: [
        "android.hardware.graphics.bufferqueue@1.0",
        "android.hardware.media.bufferpool2-V2-ndk",
        "android.hardware.media.bufferpool@2.0",
        "android.hardware.media.c2-V1-ndk",
        "android.hardware.media.c2@1.0",
        "android.hardware.media.c2@1.1",
        "android.hardware.media.c2@1.2",
        "android.hardware.media.bufferpool2-V2-ndk",
        "android.hardware.media.c2-V1-ndk",
        "libbase",
        "libbinder",
        "libbinder_ndk",
@@ -79,6 +81,10 @@ cc_library {
        "include",
    ],

    export_header_lib_headers: [
        "libapexcodecs-header",
    ],

    export_shared_lib_headers: [
        "android.hardware.media.c2@1.0",
        "android.hardware.media.c2@1.1",
@@ -89,5 +95,4 @@ cc_library {
        "libcodec2_hidl_client@1.2",
        "libcodec2_vndk",
    ],

}
+295 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 "ApexCodecsLazy"
#include <log/log.h>

#include <mutex>

#include <dlfcn.h>

#include <android-base/no_destructor.h>
#include <apex/ApexCodecs.h>
#include <utils/RWLock.h>

using android::RWLock;

namespace {

// This file provides a lazy interface to libapexcodecs.so to address early boot dependencies.

// Method pointers to libapexcodecs methods are held in an array which simplifies checking
// all pointers are initialized.
enum MethodIndex {
    k_ApexCodec_Component_create,
    k_ApexCodec_Component_destroy,
    k_ApexCodec_Component_flush,
    k_ApexCodec_Component_getConfigurable,
    k_ApexCodec_Component_process,
    k_ApexCodec_Component_start,
    k_ApexCodec_Component_reset,
    k_ApexCodec_Configurable_config,
    k_ApexCodec_Configurable_query,
    k_ApexCodec_Configurable_querySupportedParams,
    k_ApexCodec_Configurable_querySupportedValues,
    k_ApexCodec_GetComponentStore,
    k_ApexCodec_ParamDescriptors_getDescriptor,
    k_ApexCodec_ParamDescriptors_getIndices,
    k_ApexCodec_ParamDescriptors_release,
    k_ApexCodec_SettingResults_getResultAtIndex,
    k_ApexCodec_SettingResults_release,
    k_ApexCodec_SupportedValues_getTypeAndValues,
    k_ApexCodec_SupportedValues_release,
    k_ApexCodec_Traits_get,

    // Marker for count of methods
    k_MethodCount
};

class ApexCodecsLazyLoader {
public:
    ApexCodecsLazyLoader() = default;

    static ApexCodecsLazyLoader &Get() {
        static ::android::base::NoDestructor<ApexCodecsLazyLoader> sLoader;
        return *sLoader;
    }

    void *getMethodAt(enum MethodIndex index) {
        RWLock::AutoRLock l(mLock);
        if (mInit) {
            return mMethods[index];
        } else {
            mLock.unlock();
            if (!init()) {
                return nullptr;
            }
            mLock.readLock();
            return mMethods[index];
        }
    }

private:
    static void* LoadLibapexcodecs(int dlopen_flags) {
        return dlopen("libapexcodecs.so", dlopen_flags);
    }

    // Initialization and symbol binding.
    void bindSymbol_l(void* handle, const char* name, enum MethodIndex index) {
        void* symbol = dlsym(handle, name);
        ALOGI_IF(symbol == nullptr, "Failed to find symbol '%s' in libapexcodecs.so: %s",
                 name, dlerror());
        mMethods[index] = symbol;
    }

    bool init() {
        {
            RWLock::AutoRLock l(mLock);
            if (mInit) {
                return true;
            }
        }
        void* handle = LoadLibapexcodecs(RTLD_NOW);
        if (handle == nullptr) {
            ALOGI("Failed to load libapexcodecs.so: %s", dlerror());
            return false;
        }

        RWLock::AutoWLock l(mLock);
#undef BIND_SYMBOL
#define BIND_SYMBOL(name) bindSymbol_l(handle, #name, k_##name);
        BIND_SYMBOL(ApexCodec_Component_create);
        BIND_SYMBOL(ApexCodec_Component_destroy);
        BIND_SYMBOL(ApexCodec_Component_flush);
        BIND_SYMBOL(ApexCodec_Component_getConfigurable);
        BIND_SYMBOL(ApexCodec_Component_process);
        BIND_SYMBOL(ApexCodec_Component_start);
        BIND_SYMBOL(ApexCodec_Component_reset);
        BIND_SYMBOL(ApexCodec_Configurable_config);
        BIND_SYMBOL(ApexCodec_Configurable_query);
        BIND_SYMBOL(ApexCodec_Configurable_querySupportedParams);
        BIND_SYMBOL(ApexCodec_Configurable_querySupportedValues);
        BIND_SYMBOL(ApexCodec_GetComponentStore);
        BIND_SYMBOL(ApexCodec_ParamDescriptors_getDescriptor);
        BIND_SYMBOL(ApexCodec_ParamDescriptors_getIndices);
        BIND_SYMBOL(ApexCodec_ParamDescriptors_release);
        BIND_SYMBOL(ApexCodec_SettingResults_getResultAtIndex);
        BIND_SYMBOL(ApexCodec_SettingResults_release);
        BIND_SYMBOL(ApexCodec_SupportedValues_getTypeAndValues);
        BIND_SYMBOL(ApexCodec_SupportedValues_release);
        BIND_SYMBOL(ApexCodec_Traits_get);
#undef BIND_SYMBOL

        // Check every symbol is bound.
        for (int i = 0; i < k_MethodCount; ++i) {
            if (mMethods[i] == nullptr) {
                ALOGI("Uninitialized method in libapexcodecs_lazy at index: %d", i);
                return false;
            }
        }
        mInit = true;
        return true;
    }

    RWLock mLock;
    // Table of methods pointers in libapexcodecs APIs.
    void* mMethods[k_MethodCount];
    bool mInit{false};
};

}  // anonymous namespace

#define INVOKE_METHOD(name, returnIfNull, args...)                          \
    do {                                                                    \
        void* method = ApexCodecsLazyLoader::Get().getMethodAt(k_##name);   \
        if (!method) return (returnIfNull);                                 \
        return reinterpret_cast<decltype(&name)>(method)(args);             \
    } while (0)

//
// Forwarding for methods in ApexCodecs.h.
//

ApexCodec_ComponentStore *ApexCodec_GetComponentStore() {
    INVOKE_METHOD(ApexCodec_GetComponentStore, nullptr);
}

ApexCodec_ComponentTraits *ApexCodec_Traits_get(
        ApexCodec_ComponentStore *store, size_t index) {
    INVOKE_METHOD(ApexCodec_Traits_get, nullptr, store, index);
}

ApexCodec_Status ApexCodec_Component_create(
        ApexCodec_ComponentStore *store, const char *name, ApexCodec_Component **comp) {
    INVOKE_METHOD(ApexCodec_Component_create, APEXCODEC_STATUS_OMITTED, store, name, comp);
}

void ApexCodec_Component_destroy(ApexCodec_Component *comp) {
    INVOKE_METHOD(ApexCodec_Component_destroy, void(), comp);
}

ApexCodec_Status ApexCodec_Component_start(ApexCodec_Component *comp) {
    INVOKE_METHOD(ApexCodec_Component_start, APEXCODEC_STATUS_OMITTED, comp);
}

ApexCodec_Status ApexCodec_Component_flush(ApexCodec_Component *comp) {
    INVOKE_METHOD(ApexCodec_Component_flush, APEXCODEC_STATUS_OMITTED, comp);
}

ApexCodec_Status ApexCodec_Component_reset(ApexCodec_Component *comp) {
    INVOKE_METHOD(ApexCodec_Component_reset, APEXCODEC_STATUS_OMITTED, comp);
}

ApexCodec_Configurable *ApexCodec_Component_getConfigurable(
        ApexCodec_Component *comp) {
    INVOKE_METHOD(ApexCodec_Component_getConfigurable, nullptr, comp);
}

ApexCodec_Status ApexCodec_SupportedValues_getTypeAndValues(
        ApexCodec_SupportedValues *supportedValues,
        ApexCodec_SupportedValuesType *type,
        ApexCodec_SupportedValuesNumberType *numberType,
        ApexCodec_Value **values,
        uint32_t *numValues) {
    INVOKE_METHOD(ApexCodec_SupportedValues_getTypeAndValues, APEXCODEC_STATUS_OMITTED,
                  supportedValues, type, numberType, values, numValues);
}

void ApexCodec_SupportedValues_release(ApexCodec_SupportedValues *values) {
    INVOKE_METHOD(ApexCodec_SupportedValues_release, void(), values);
}

ApexCodec_Status ApexCodec_SettingResults_getResultAtIndex(
        ApexCodec_SettingResults *results,
        size_t index,
        ApexCodec_SettingResultFailure *failure,
        ApexCodec_ParamFieldValues *field,
        ApexCodec_ParamFieldValues **conflicts,
        size_t *numConflicts) {
    INVOKE_METHOD(ApexCodec_SettingResults_getResultAtIndex, APEXCODEC_STATUS_OMITTED,
                  results, index, failure, field, conflicts, numConflicts);
}

void ApexCodec_SettingResults_release(ApexCodec_SettingResults *results) {
    INVOKE_METHOD(ApexCodec_SettingResults_release, void(), results);
}

ApexCodec_Status ApexCodec_Component_process(
        ApexCodec_Component *comp,
        const ApexCodec_Buffer *input,
        ApexCodec_Buffer *output,
        size_t *consumed,
        size_t *produced) {
    INVOKE_METHOD(ApexCodec_Component_process, APEXCODEC_STATUS_OMITTED,
                  comp, input, output, consumed, produced);
}

ApexCodec_Status ApexCodec_Configurable_config(
        ApexCodec_Configurable *comp,
        ApexCodec_LinearBuffer *config,
        ApexCodec_SettingResults **results) {
    INVOKE_METHOD(ApexCodec_Configurable_config, APEXCODEC_STATUS_OMITTED, comp, config, results);
}

ApexCodec_Status ApexCodec_Configurable_query(
        ApexCodec_Configurable *comp,
        uint32_t indices[],
        size_t numIndices,
        ApexCodec_LinearBuffer *config,
        size_t *writtenOrRequested) {
    INVOKE_METHOD(ApexCodec_Configurable_query, APEXCODEC_STATUS_OMITTED,
                  comp, indices, numIndices, config, writtenOrRequested);
}

ApexCodec_Status ApexCodec_ParamDescriptors_getIndices(
        ApexCodec_ParamDescriptors *descriptors,
        uint32_t **indices,
        size_t *numIndices) {
    INVOKE_METHOD(ApexCodec_ParamDescriptors_getIndices, APEXCODEC_STATUS_OMITTED,
                  descriptors, indices, numIndices);
}

ApexCodec_Status ApexCodec_ParamDescriptors_getDescriptor(
        ApexCodec_ParamDescriptors *descriptors,
        uint32_t index,
        ApexCodec_ParamAttribute *attr,
        const char **name,
        uint32_t **dependencies,
        size_t *numDependencies) {
    INVOKE_METHOD(ApexCodec_ParamDescriptors_getDescriptor, APEXCODEC_STATUS_OMITTED,
                  descriptors, index, attr, name, dependencies, numDependencies);
}

ApexCodec_Status ApexCodec_ParamDescriptors_release(
        ApexCodec_ParamDescriptors *descriptors) {
    INVOKE_METHOD(ApexCodec_ParamDescriptors_release, APEXCODEC_STATUS_OMITTED, descriptors);
}

ApexCodec_Status ApexCodec_Configurable_querySupportedParams(
        ApexCodec_Configurable *comp,
        ApexCodec_ParamDescriptors **descriptors) {
    INVOKE_METHOD(ApexCodec_Configurable_querySupportedParams, APEXCODEC_STATUS_OMITTED,
                  comp, descriptors);
}

ApexCodec_Status ApexCodec_Configurable_querySupportedValues(
        ApexCodec_Configurable *comp,
        ApexCodec_SupportedValuesQuery *queries,
        size_t numQueries) {
    INVOKE_METHOD(ApexCodec_Configurable_querySupportedValues, APEXCODEC_STATUS_OMITTED,
                  comp, queries, numQueries);
}
+952 −31

File changed.

Preview size limit exceeded, changes collapsed.

+38 −0
Original line number Diff line number Diff line
@@ -112,6 +112,10 @@ namespace android::hardware::media::omx::V1_0 {
struct IGraphicBufferSource;
}  // namespace android::hardware::media::omx::V1_0

struct ApexCodec_ComponentStore;
struct ApexCodec_Component;
struct ApexCodec_Configurable;

namespace android {

// This class is supposed to be called Codec2Client::Configurable, but forward
@@ -148,6 +152,7 @@ struct Codec2ConfigurableClient {

    explicit Codec2ConfigurableClient(const sp<HidlBase> &hidlBase);
    explicit Codec2ConfigurableClient(const std::shared_ptr<AidlBase> &aidlBase);
    Codec2ConfigurableClient(ApexCodec_Configurable *base, const C2String &name);

    const C2String& getName() const;

@@ -172,6 +177,7 @@ struct Codec2ConfigurableClient {
private:
    struct HidlImpl;
    struct AidlImpl;
    struct ApexImpl;

    const std::unique_ptr<ImplBase> mImpl;
};
@@ -282,12 +288,16 @@ struct Codec2Client : public Codec2ConfigurableClient {
            std::shared_ptr<AidlBase> const& base,
            std::shared_ptr<Codec2ConfigurableClient::AidlBase> const& configurable,
            size_t serviceIndex);
    Codec2Client(
            ApexCodec_ComponentStore* base,
            size_t serviceIndex);

protected:
    sp<HidlBase1_0> mHidlBase1_0;
    sp<HidlBase1_1> mHidlBase1_1;
    sp<HidlBase1_2> mHidlBase1_2;
    std::shared_ptr<AidlBase> mAidlBase;
    ApexCodec_ComponentStore* mApexBase{nullptr};

    // Finds the first store where the predicate returns C2_OK and returns the
    // last predicate result. The predicate will be tried on all stores. The
@@ -325,6 +335,20 @@ protected:
    std::vector<C2Component::Traits> _listComponents(bool* success) const;

    class Cache;

private:
    c2_status_t createComponent_aidl(
            C2String const& name,
            std::shared_ptr<Listener> const& listener,
            std::shared_ptr<Component>* const component);
    c2_status_t createComponent_hidl(
            C2String const& name,
            std::shared_ptr<Listener> const& listener,
            std::shared_ptr<Component>* const component);
    c2_status_t createComponent_apex(
            C2String const& name,
            std::shared_ptr<Listener> const& listener,
            std::shared_ptr<Component>* const component);
};

struct Codec2Client::Interface : public Codec2Client::Configurable {
@@ -508,11 +532,16 @@ struct Codec2Client::Component : public Codec2Client::Configurable {

    c2_status_t disconnectFromInputSurface();

    c2_status_t initApexHandler(
            const std::shared_ptr<Listener> &listener,
            const std::shared_ptr<Component> &comp);

    // base cannot be null.
    Component(const sp<HidlBase>& base);
    Component(const sp<HidlBase1_1>& base);
    Component(const sp<HidlBase1_2>& base);
    Component(const std::shared_ptr<AidlBase>& base);
    Component(ApexCodec_Component* base, const C2String& name);

    ~Component();

@@ -521,12 +550,16 @@ protected:
    sp<HidlBase1_1> mHidlBase1_1;
    sp<HidlBase1_2> mHidlBase1_2;
    std::shared_ptr<AidlBase> mAidlBase;
    ApexCodec_Component *mApexBase{nullptr};

    struct HidlBufferPoolSender;
    struct AidlBufferPoolSender;
    std::unique_ptr<HidlBufferPoolSender> mHidlBufferPoolSender;
    std::unique_ptr<AidlBufferPoolSender> mAidlBufferPoolSender;

    class ApexHandler;
    std::unique_ptr<ApexHandler> mApexHandler;

    struct OutputBufferQueue;
    std::unique_ptr<OutputBufferQueue> mOutputBufferQueue;

@@ -547,6 +580,11 @@ protected:
            const std::shared_ptr<Listener>& listener);
    sp<::android::hardware::hidl_death_recipient> mDeathRecipient;

    // This is a map of block pools created for APEX components in the client.
    // Note that the APEX codec API requires output buffers to be passed from the client,
    // so the client creates and keeps track of the block pools here.
    std::map<C2BlockPool::local_id_t, std::shared_ptr<C2BlockPool>> mBlockPools;

    friend struct Codec2Client;

    struct HidlListener;
+9 −0
Original line number Diff line number Diff line
@@ -40,6 +40,15 @@ cc_defaults {

}

cc_library_headers {
    name: "libapexcodecs-header",
    visibility: [
        "//frameworks/av/apex:__subpackages__",
        "//frameworks/av/media/codec2/hal/client",
    ],
    export_include_dirs: ["include"],
}

cc_library {
    name: "libapexcodecs-testing",
    defaults: ["libapexcodecs-defaults"],