栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Android 10 源码】深入理解 software Codec2 服务启动

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Android 10 源码】深入理解 software Codec2 服务启动

MediaCodec 系列文章:

  1. 【Android 10 源码】深入理解 MediaCodec 硬解码初始化
  2. 【Android 10 源码】深入理解 Omx 初始化
  3. 【Android 10 源码】深入理解 codecservice 启动
  4. 【Android 10 源码】深入理解 software Codec2 服务启动
  5. 【Android 10 源码】深入理解构建 MediaCodec 列表:buildMediaCodecList

经过前面几节分析不难得出想要支持 Codec2 框架,需要实现其要求的 hal 接口,并实现相应的支撑服务。这里以源码中实现 software Codec2 服务启动为例进行分析。

software Codec2 服务启动位于 CodecServiceRegistrant.cpp 中。在 rk3399 Android 10 平台上可以看到启动 Log:

CodecServiceRegistrant: Creating software Codec2 service…

CodecServiceRegistrant: Software Codec2 service created.

可是 RegisterCodecServices() 并不是 main 函数,说明这并不是代码起点。

  1. 调用 android::GetCodec2PlatformComponentStore() 创建 C2PlatformComponentStore 对象;
  2. 将 C2PlatformComponentStore 对象作为入参构建 utils::ComponentStore 对象。

frameworks/av/services/mediacodec/registrant/CodecServiceRegistrant.cpp

extern "C" void RegisterCodecServices() {
    using namespace ::android::hardware::media::c2::V1_0;
    LOG(INFO) << "Creating software Codec2 service...";
    android::sp store =
        new utils::ComponentStore(
                android::GetCodec2PlatformComponentStore());
    if (store == nullptr) {
        LOG(ERROR) <<
                "Cannot create software Codec2 service.";
    } else {
        if (store->registerAsService("software") != android::OK) {
            LOG(ERROR) <<
                    "Cannot register software Codec2 service.";
        } else {
            LOG(INFO) <<
                    "Software Codec2 service created.";
        }
    }
}

重点来了,main_swcodecservice.cpp main 函数中发现了启动 software Codec2 service 的调用,启动就是从这里开始的。

frameworks/av/services/mediacodec/main_swcodecservice.cpp

extern "C" void RegisterCodecServices();

int main(int argc __unused, char** argv)
{
    LOG(INFO) << "media swcodec service starting";
    signal(SIGPIPE, SIG_IGN);
    SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
    strcpy(argv[0], "media.swcodec");

    ::android::hardware::configureRpcThreadpool(64, false);

    RegisterCodecServices();

    ::android::hardware::joinRpcThreadpool();
}

android::GetCodec2PlatformComponentStore() 函数定义在 C2PlatformSupport.h 中。注释解释这个函数的作用是返回平台组件仓库(store),如果返回为空说明获取失败了。

frameworks/av/media/codec2/vndk/include/C2PlatformSupport.h

namespace android {

std::shared_ptr GetCodec2PlatformComponentStore();
}
  1. 创建一个指向 C2ComponentStore 的“弱”指针;
  2. “弱”指针上调用 C2ComponentStore lock() 获取对象;
  3. 如果上一步无法获取,调用 C2PlatformComponentStore 构造函数构造 C2PlatformComponentStore 对象。

第一次启动务必会调用到 C2PlatformComponentStore 无参构造器。

frameworks/av/media/codec2/vndk/C2Store.cpp

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

初始化了三个变量 mVisited、mReflector 和 mInterface。然后将各种 so 路径添加到 std::map。不难看出这些 so 就是各种软编解码具体实现。

frameworks/av/media/codec2/vndk/C2Store.cpp

C2PlatformComponentStore::C2PlatformComponentStore()
    : mVisited(false),
      mReflector(std::make_shared()),
      mInterface(mReflector) {

    auto emplace = [this](const char *libPath) {
        mComponents.emplace(libPath, libPath);
    };

    // TODO: move this also into a .so so it can be updated
    emplace("libcodec2_soft_aacdec.so");
    emplace("libcodec2_soft_aacenc.so");
    emplace("libcodec2_soft_amrnbdec.so");
    emplace("libcodec2_soft_amrnbenc.so");
    emplace("libcodec2_soft_amrwbdec.so");
    emplace("libcodec2_soft_amrwbenc.so");
    emplace("libcodec2_soft_av1dec.so");
    emplace("libcodec2_soft_avcdec.so");
    emplace("libcodec2_soft_avcenc.so");
    emplace("libcodec2_soft_flacdec.so");
    emplace("libcodec2_soft_flacenc.so");
    emplace("libcodec2_soft_g711alawdec.so");
    emplace("libcodec2_soft_g711mlawdec.so");
    emplace("libcodec2_soft_gsmdec.so");
    emplace("libcodec2_soft_h263dec.so");
    emplace("libcodec2_soft_h263enc.so");
    emplace("libcodec2_soft_hevcdec.so");
    emplace("libcodec2_soft_hevcenc.so");
    emplace("libcodec2_soft_mp3dec.so");
    emplace("libcodec2_soft_mpeg2dec.so");
    emplace("libcodec2_soft_mpeg4dec.so");
    emplace("libcodec2_soft_mpeg4enc.so");
    emplace("libcodec2_soft_opusdec.so");
    emplace("libcodec2_soft_opusenc.so");
    emplace("libcodec2_soft_rawdec.so");
    emplace("libcodec2_soft_vorbisdec.so");
    emplace("libcodec2_soft_vp8dec.so");
    emplace("libcodec2_soft_vp8enc.so");
    emplace("libcodec2_soft_vp9dec.so");
    emplace("libcodec2_soft_vp9enc.so");
}
  1. 构造 CachedConfigurable 对象赋值给 mConfigurable;
  2. 调用 android::GetCodec2PlatformComponentStore() 获取指向 C2ComponentStore 的共享指针;
  3. 调用 SetPreferredCodec2ComponentStore(…) 如果平台分配器 store 是活的使用 C2ComponentStore 共享指针进行更新;
  4. 调用 C2ComponentStore getParamReflector() 检索结构描述符;
  5. CachedConfigurable 对象调用其 init(…) 函数初始化。

frameworks/av/media/codec2/hidl/1.0/utils/ComponentStore.cpp

ComponentStore::ComponentStore(const std::shared_ptr& store)
      : mConfigurable{new CachedConfigurable(std::make_unique(store))},
        mStore{store} {

    std::shared_ptr platformStore = android::GetCodec2PlatformComponentStore();
    SetPreferredCodec2ComponentStore(store);

    // Retrieve struct descriptors
    mParamReflector = mStore->getParamReflector();

    // Retrieve supported parameters from store
    mInit = mConfigurable->init(this);
}

CachedConfigurable 构造函数非常简单,仅仅将入参 ConfigurableC2Intf(实际为指向 StoreIntf 的结构体)(通用 Codec 2.0 接口包装器) 指针用来初始化其 mIntf 字段。

frameworks/av/media/codec2/hidl/1.0/utils/Configurable.cpp

CachedConfigurable::CachedConfigurable(
        std::unique_ptr&& intf)
      : mIntf{std::move(intf)} {
}
  1. 使用入参更新全局变量 gPreferredComponentStore,实际是一个 std::shared_ptr 指针;
  2. 如果平台分配器 store 是活的,使用 C2ComponentStore 共享指针进行更新。

frameworks/av/media/codec2/vndk/C2Store.cpp

namespace {
    std::mutex gPreferredComponentStoreMutex;
    std::shared_ptr gPreferredComponentStore;

    std::mutex gPlatformAllocatorStoreMutex;
    std::weak_ptr gPlatformAllocatorStore;
}
......
void SetPreferredCodec2ComponentStore(std::shared_ptr componentStore) {
    static std::mutex mutex;
    std::lock_guard lock(mutex); // don't interleve set-s

    // update preferred store
    {
        std::lock_guard lock(gPreferredComponentStoreMutex);
        gPreferredComponentStore = componentStore;
    }

    // update platform allocator's store as well if it is alive
    std::shared_ptr allocatorStore;
    {
        std::lock_guard lock(gPlatformAllocatorStoreMutex);
        allocatorStore = gPlatformAllocatorStore.lock();
    }
    if (allocatorStore) {
        allocatorStore->setComponentStore(componentStore);
    }
}
  1. 使用入参更新 _mComponentStore 字段;
  2. 调用 UseComponentStoreForIonAllocator() 函数,给 Ion 分配器使用组件 store。

frameworks/av/media/codec2/vndk/C2Store.cpp

void C2PlatformAllocatorStoreImpl::setComponentStore(std::shared_ptr store) {
    // technically this set lock is not needed, but is here for safety in case we add more
    // getter orders
    std::lock_guard lock(_mComponentStoreSetLock);
    {
        std::lock_guard lock(_mComponentStoreReadLock);
        _mComponentStore = store;
    }
    std::shared_ptr allocator;
    {
        std::lock_guard lock(gIonAllocatorMutex);
        allocator = gIonAllocator.lock();
    }
    if (allocator) {
        UseComponentStoreForIonAllocator(allocator, store);
    }
}
  1. minUsage 赋初值等于 0,maxUsage 初值则是结合了 C2MemoryUsage::CPU_READ 和 C2MemoryUsage::CPU_WRITE 的期望值;
  2. 调用 getpagesize() 获取页面大小赋值给 blockSize;
  3. 构建一个查询条件容器(包括 usage 和 capacity) std::vector,调用 C2ComponentStore querySupportedValues_sm(…) 进行查询;
  4. 根据查询结果更新 minUsage、maxUsage 和 blockSize;
  5. 构造一个函数指针 C2AllocatorIon::UsageMapperFn mapper 指向匿名函数,匿名函数的作用是调用 C2ComponentStore config_sm(…) 进行配置 C2StoreIonUsageInfo(此结构内部包含了最小和最大使用量以及块大小 ),配置成功后更新匿名函数入参 align、heapMask 和 flags;
  6. 调用 C2AllocatorIon setUsageMapper(…) 设置 Mapper。

frameworks/av/media/codec2/vndk/C2Store.cpp

void UseComponentStoreForIonAllocator(
        const std::shared_ptr allocator,
        std::shared_ptr store) {
    C2AllocatorIon::UsageMapperFn mapper;
    uint64_t minUsage = 0;
    uint64_t maxUsage = C2MemoryUsage(C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE).expected;
    size_t blockSize = getpagesize();

    // query min and max usage as well as block size via supported values
    C2StoreIonUsageInfo usageInfo;
    std::vector query = {
        C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.usage)),
        C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.capacity)),
    };
    c2_status_t res = store->querySupportedValues_sm(query);
    if (res == C2_OK) {
        if (query[0].status == C2_OK) {
            const C2FieldSupportedValues &fsv = query[0].values;
            if (fsv.type == C2FieldSupportedValues::FLAGS && !fsv.values.empty()) {
                minUsage = fsv.values[0].u64;
                maxUsage = 0;
                for (C2Value::Primitive v : fsv.values) {
                    maxUsage |= v.u64;
                }
            }
        }
        if (query[1].status == C2_OK) {
            const C2FieldSupportedValues &fsv = query[1].values;
            if (fsv.type == C2FieldSupportedValues::RANGE && fsv.range.step.u32 > 0) {
                blockSize = fsv.range.step.u32;
            }
        }

        mapper = [store](C2MemoryUsage usage, size_t capacity,
                         size_t *align, unsigned *heapMask, unsigned *flags) -> c2_status_t {
            if (capacity > UINT32_MAX) {
                return C2_BAD_VALUE;
            }
            C2StoreIonUsageInfo usageInfo = { usage.expected, capacity };
            std::vector> failures; // TODO: remove
            c2_status_t res = store->config_sm({&usageInfo}, &failures);
            if (res == C2_OK) {
                *align = usageInfo.minAlignment;
                *heapMask = usageInfo.heapMask;
                *flags = usageInfo.allocFlags;
            }
            return res;
        };
    }

    allocator->setUsageMapper(mapper, minUsage, maxUsage, blockSize);
}

根据注释不难理解 UsageMapperFn 的作用,分配器使用的 usage mapper 函数,函数入参:(usage, capacity) ,函数返回值 :(align, heapMask, flags)。容量与默认块大小(默认页大小)对齐,以减少缓存开销。

setUsageMapper(…) 的作用是更新用于后续新分配的 usage mapper,以及支持的最小和最大 usage 掩码和用于 mapper 的默认块大小。

frameworks/av/media/codec2/vndk/include/C2AllocatorIon.h

namespace android {

class C2AllocatorIon : public C2Allocator {
public:
    // Usage mapper function used by the allocator
    //   (usage, capacity) => (align, heapMask, flags)
    //
    // capacity is aligned to the default block-size (defaults to page size) to reduce caching
    // overhead
    typedef std::function UsageMapperFn;
    ......
    
    void setUsageMapper(
            const UsageMapperFn &mapper, uint64_t minUsage, uint64_t maxUsage, uint64_t blockSize);
    ......
}

不难得出 maxUsage = C2MemoryUsage(C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE).expected,实际为 0x001 | 0x100 = 0x101。

frameworks/av/media/codec2/core/include/C2Bufferbase.h

struct C2MemoryUsage {
// public:
    
    enum read_t : uint64_t {
        
        CPU_READ        = 1 << 0,
        ......
    };

    
    enum write_t : uint64_t {
        
        CPU_WRITE        = 1 << 2,
        ......
    };
    ......
    
    inline C2MemoryUsage(uint64_t consumer, uint64_t producer)
        : expected(consumer | producer) { }
    ......
    uint64_t expected; // expected buffer usage
};

由于是 android 10 系统所以实际一定满足 >= ANDROID_API_L 的条件。

bionic/libc/include/unistd.h

#if __ANDROID_API__ >= __ANDROID_API_L__
int getpagesize(void) __INTRODUCED_IN(21);
#else
static __inline__ int getpagesize(void) {
  return sysconf(_SC_PAGESIZE);
}
#endif

直接返回了 PAGE_SIZE,PAGE_SIZE 定义在 /sys/user.h 下,其值等于 4096,也就是 4KB 页面大小。至于这个地方为啥没使用 sysconf(3) 系统调用,注释中做了说明是为了防止静态库变的臃肿,因为会把 stdio 相关代码合进来。

bionic/libc/bionic/getpagesize.cpp

// Portable code should use sysconf(_SC_PAGE_SIZE) directly instead.
int getpagesize() {
  // We dont use sysconf(3) here because that drags in stdio, which makes static binaries fat.
  return PAGE_SIZE;
}

bionic/libc/include/sys/user.h

#define PAGE_SIZE 4096

根据前面的分析,C2ComponentStore 实际指向 C2PlatformComponentStore。

frameworks/av/media/codec2/vndk/C2Store.cpp

c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
        std::vector &fields) const {
    return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
}

mInterface 初始化传入了指向 C2ReflectorHelper 的共享指针。具体 Interface 结构体构造过程不再展开。

frameworks/av/media/codec2/vndk/C2Store.cpp

class C2PlatformComponentStore : public C2ComponentStore {
    ......
    private:
    struct Interface : public C2InterfaceHelper {
        std::shared_ptr mIonUsageInfo;

        Interface(std::shared_ptr reflector)
            : C2InterfaceHelper(reflector) {
            setDerivedInstance(this);

            struct Setter {
                static C2R setIonUsage(bool , C2P &me) {
                    me.set().heapMask = ~0;
                    me.set().allocFlags = 0;
                    me.set().minAlignment = 0;
                    return C2R::Ok();
                }
            };

            addParameter(
                DefineParam(mIonUsageInfo, "ion-usage")
                .withDefault(new C2StoreIonUsageInfo())
                .withFields({
                    C2F(mIonUsageInfo, usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
                    C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
                    C2F(mIonUsageInfo, heapMask).any(),
                    C2F(mIonUsageInfo, allocFlags).flags({}),
                    C2F(mIonUsageInfo, minAlignment).equalTo(0)
                })
                .withSetter(Setter::setIonUsage)
                .build());
        }
    };        
    ......  
}

回到主题,Interface querySupportedValues(…) 实际是调用父类 C2InterfaceHelper querySupportedValues(…) 实现的。同样 C2PlatformComponentStore::config_sm(…) 内部调用 Interface config(…) 实现,其实也是调用父类 C2InterfaceHelper config(…) 。

c2_status_t C2PlatformComponentStore::config_sm(
        const std::vector ¶ms,
        std::vector> *const failures) {
    return mInterface.config(params, C2_MAY_BLOCK, failures);
}

此处直接返回了 mReflector,这个字段是在 C2PlatformComponentStore 构造器中初始化的,其为指向 C2ReflectorHelper(实现参数反射,这个类是动态的,设计成由多个接口共享。这允许接口根据需要添加结构描述符) 的指针。

std::shared_ptr C2PlatformComponentStore::getParamReflector() const {
    return mReflector;
}

最后来分析一番 CachedConfigurable 对象调用其 init(…) 函数初始化。

主要功能为从存储区检索支持的参数。前面分析道 mIntf 指向 StoreIntf 结构体,所以此处调用实际为调用 StoreIntf querySupportedParams(…) 函数,最后调用 ComponentStore validateSupportedParams(…) 校验支持参数。

frameworks/av/media/codec2/hidl/1.0/utils/Configurable.cpp

c2_status_t CachedConfigurable::init(ComponentStore* store) {
    // 从存储区检索支持的参数
    c2_status_t init = mIntf->querySupportedParams(&mSupportedParams);
    c2_status_t validate = store->validateSupportedParams(mSupportedParams);
    return init == C2_OK ? C2_OK : validate;
}

StoreIntf querySupportedParams(…) 分发给了 C2ComponentStore querySupportedParams_nb(…) 方法。

frameworks/av/media/codec2/hidl/1.0/utils/ComponentStore.cpp

struct StoreIntf : public ConfigurableC2Intf {
    StoreIntf(const std::shared_ptr& store)
          : ConfigurableC2Intf{store ? store->getName() : "", 0},
            mStore{store} {
    }    
    ......
    virtual c2_status_t querySupportedParams(
            std::vector> *const params
            ) const override {
        return mStore->querySupportedParams_nb(params);
    }    
    ......
protected:
    std::shared_ptr mStore;
};
}

mInterface 是在 C2PlatformComponentStore 构造器中初始化的,mInterface 是一个 Interface 结构(继承自 C2InterfaceHelper),所以调用其 querySupportedParams(…) 函数实际实现在其父类 C2InterfaceHelper 中。

frameworks/av/media/codec2/vndk/C2Store.cpp

c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
        std::vector> *const params) const {
    return mInterface.querySupportedParams(params);
}

C2InterfaceHelper::querySupportedParams(…) 内部仅仅调用了 C2InterfaceHelper::FactoryImpl querySupportedParams(…) 方法。

frameworks/av/media/codec2/vndk/util/C2InterfaceHelper.cpp

c2_status_t C2InterfaceHelper::querySupportedParams(
        std::vector> *const params) const {
    std::lock_guard lock(mMutex);
    return _mFactory->querySupportedParams(params);
}

遍历 _mParams(std::map)将其 value 转化为 C2ParamDescriptor 添加到入参提供的容器。

frameworks/av/media/codec2/vndk/util/C2InterfaceHelper.cpp

struct C2InterfaceHelper::FactoryImpl : public C2InterfaceHelper::Factory {
    ......
public:
    ......
    c2_status_t querySupportedParams(
            std::vector> *const params) const {
        for (const auto &it : _mParams) {
            // TODO: change querySupportedParams signature?
            params->push_back(
                    std::const_pointer_cast(it.second->getDescriptor()));
        }
        // TODO: handle errors
        return C2_OK;
    }
    ......
}

逐个遍历入参容器中的 C2ParamDescriptor,将 map 中不存在的 CoreIndex-C2ParamDescriptor 结构对插入到 map(std::map)中。

frameworks/av/media/codec2/hidl/1.0/utils/ComponentStore.cpp

c2_status_t ComponentStore::validateSupportedParams(
        const std::vector>& params) {
    c2_status_t res = C2_OK;

    for (const std::shared_ptr &desc : params) {
        if (!desc) {
            // All descriptors should be valid
            res = res ? res : C2_BAD_VALUE;
            continue;
        }
        C2Param::CoreIndex coreIndex = desc->index().coreIndex();
        std::lock_guard lock(mStructDescriptorsMutex);
        auto it = mStructDescriptors.find(coreIndex);
        if (it == mStructDescriptors.end()) {
            std::shared_ptr structDesc =
                    mParamReflector->describe(coreIndex);
            if (!structDesc) {
                // All supported params must be described
                res = C2_BAD_INDEX;
            }
            mStructDescriptors.insert({ coreIndex, structDesc });
        }
    }
    return res;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/346032.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号