Loading media/codec2/hidl/client/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -30,8 +30,8 @@ cc_library { ], export_shared_lib_headers: [ "libcodec2_hidl@1.0", "libcodec2", "libcodec2_hidl@1.0", ], } Loading media/codec2/hidl/client/client.cpp +272 −111 Original line number Diff line number Diff line Loading @@ -21,8 +21,12 @@ #include <codec2/hidl/client.h> #include <deque> #include <iterator> #include <limits> #include <map> #include <mutex> #include <sstream> #include <thread> #include <type_traits> #include <vector> Loading @@ -39,6 +43,7 @@ #include <android/hardware/media/c2/1.0/IComponentListener.h> #include <android/hardware/media/c2/1.0/IComponentStore.h> #include <android/hardware/media/c2/1.0/IConfigurable.h> #include <android/hidl/manager/1.2/IServiceManager.h> #include <C2Debug.h> #include <C2BufferPriv.h> Loading Loading @@ -70,35 +75,181 @@ namespace /* unnamed */ { // c2_status_t value that corresponds to hwbinder transaction failure. constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED; // List of known IComponentStore services in the decreasing order of preference. constexpr const char* kClientNames[] = { "default", "software", }; // Number of known IComponentStore services. constexpr size_t kNumClients = std::extent<decltype(kClientNames)>::value; typedef std::array<std::shared_ptr<Codec2Client>, kNumClients> ClientList; // Returns the list of IComponentStore service names that are available on the // device. This list is specified at the build time in manifest files. // Note: A software service will have "_software" as a suffix. std::vector<std::string> const& getServiceNames() { static std::vector<std::string> sServiceNames{[]() { using ::android::hardware::media::c2::V1_0::IComponentStore; using ::android::hidl::manager::V1_2::IServiceManager; while (true) { sp<IServiceManager> serviceManager = IServiceManager::getService(); CHECK(serviceManager) << "Hardware service manager is not running."; // There are three categories of services based on names. std::vector<std::string> defaultNames; // Prefixed with "default" std::vector<std::string> vendorNames; // Prefixed with "vendor" std::vector<std::string> otherNames; // Others Return<void> transResult; transResult = serviceManager->listManifestByInterface( IComponentStore::descriptor, [&defaultNames, &vendorNames, &otherNames]( hidl_vec<hidl_string> const& instanceNames) { for (hidl_string const& instanceName : instanceNames) { char const* name = instanceName.c_str(); if (strncmp(name, "default", 7) == 0) { defaultNames.emplace_back(name); } else if (strncmp(name, "vendor", 6) == 0) { vendorNames.emplace_back(name); } else { otherNames.emplace_back(name); } } }); if (transResult.isOk()) { // Sort service names in each category. std::sort(defaultNames.begin(), defaultNames.end()); std::sort(vendorNames.begin(), vendorNames.end()); std::sort(otherNames.begin(), otherNames.end()); // Concatenate the three lists in this order: default, vendor, // other. std::vector<std::string>& names = defaultNames; names.reserve(names.size() + vendorNames.size() + otherNames.size()); names.insert(names.end(), std::make_move_iterator(vendorNames.begin()), std::make_move_iterator(vendorNames.end())); names.insert(names.end(), std::make_move_iterator(otherNames.begin()), std::make_move_iterator(otherNames.end())); // Summarize to logcat. if (names.empty()) { LOG(INFO) << "No Codec2 services declared in the manifest."; } else { std::stringstream stringOutput; stringOutput << "Available Codec2 services:"; for (std::string const& name : names) { stringOutput << " \"" << name << "\""; } LOG(INFO) << stringOutput.str(); } // Convenience methods to obtain known clients. std::shared_ptr<Codec2Client> getClient(size_t index) { uint32_t serviceMask = ::android::base::GetUintProperty( "debug.media.codec2", uint32_t(0)); return Codec2Client::CreateFromService( kClientNames[index], (serviceMask & (1 << index)) != 0); return names; } LOG(ERROR) << "Could not retrieve the list of service instances of " << IComponentStore::descriptor << ". Retrying..."; } }()}; return sServiceNames; } ClientList getClientList() { ClientList list; for (size_t i = 0; i < list.size(); ++i) { list[i] = getClient(i); // Searches for a name in getServiceNames() and returns the index found. If the // name is not found, the returned index will be equal to // getServiceNames().size(). size_t getServiceIndex(char const* name) { std::vector<std::string> const& names = getServiceNames(); size_t i = 0; for (; i < names.size(); ++i) { if (name == names[i]) { break; } } return i; } } // unnamed namespace // This class caches a Codec2Client object and its component traits. The client // will be created the first time it is needed, and it can be refreshed if the // service dies (by calling invalidate()). The first time listComponents() is // called from the client, the result will be cached. class Codec2Client::Cache { // Cached client std::shared_ptr<Codec2Client> mClient; mutable std::mutex mClientMutex; // Cached component traits std::vector<C2Component::Traits> mTraits; std::once_flag mTraitsInitializationFlag; // The index of the service. This is based on getServiceNames(). size_t mIndex; // A "valid" cache object must have its mIndex set with init(). bool mValid{false}; // Called by s() exactly once to initialize the cache. The index must be a // valid index into the vector returned by getServiceNames(). Calling // init(index) will associate the cache to the service with name // getServiceNames()[index]. void init(size_t index) { mIndex = index; mValid = true; } public: Cache() = default; // Initializes mClient if needed, then returns mClient. // If the service is unavailable but listed in the manifest, this function // will block indefinitely. std::shared_ptr<Codec2Client> getClient() { CHECK(mValid) << "Uninitialized cache"; std::scoped_lock lock{mClientMutex}; if (!mClient) { mClient = Codec2Client::_CreateFromIndex(mIndex); } return mClient; } // Causes a subsequent call to getClient() to create a new client. This // function should be called after the service dies. // // Note: This function is called only by ForAllServices(). void invalidate() { CHECK(mValid) << "Uninitialized cache"; std::scoped_lock lock{mClientMutex}; mClient = nullptr; } // Returns a list of traits for components supported by the service. This // list is cached. std::vector<C2Component::Traits> const& getTraits() { CHECK(mValid) << "Uninitialized cache"; std::call_once(mTraitsInitializationFlag, [this]() { bool success{false}; // Spin until _listComponents() is successful. while (true) { std::shared_ptr<Codec2Client> client = getClient(); mTraits = client->_listComponents(&success); if (success) { break; } using namespace std::chrono_literals; static constexpr auto kServiceRetryPeriod = 5s; LOG(INFO) << "Failed to retrieve component traits from service " "\"" << getServiceNames()[mIndex] << "\". " "Retrying..."; std::this_thread::sleep_for(kServiceRetryPeriod); } return list; }); return mTraits; } } // unnamed // List() returns the list of all caches. static std::vector<Cache>& List() { static std::vector<Cache> sCaches{[]() { size_t numServices = getServiceNames().size(); std::vector<Cache> caches(numServices); for (size_t i = 0; i < numServices; ++i) { caches[i].init(i); } return caches; }()}; return sCaches; } }; // Codec2ConfigurableClient Loading Loading @@ -439,7 +590,7 @@ struct Codec2Client::Component::HidlListener : public IComponentListener { // Codec2Client Codec2Client::Codec2Client(const sp<IComponentStore>& base, std::string serviceName) size_t serviceIndex) : Configurable{ [base]() -> sp<IConfigurable> { Return<sp<IConfigurable>> transResult = Loading @@ -450,8 +601,7 @@ Codec2Client::Codec2Client(const sp<IComponentStore>& base, }() }, mBase{base}, mListed{false}, mServiceName{serviceName} { mServiceIndex{serviceIndex} { Return<sp<IClientManager>> transResult = base->getPoolClientManager(); if (!transResult.isOk()) { LOG(ERROR) << "getPoolClientManager -- transaction failed."; Loading @@ -460,6 +610,10 @@ Codec2Client::Codec2Client(const sp<IComponentStore>& base, } } std::string const& Codec2Client::getServiceName() const { return getServiceNames()[mServiceIndex]; } c2_status_t Codec2Client::createComponent( const C2String& name, const std::shared_ptr<Codec2Client::Listener>& listener, Loading Loading @@ -558,33 +712,38 @@ c2_status_t Codec2Client::createInputSurface( return status; } const std::vector<C2Component::Traits>& Codec2Client::listComponents() const { std::lock_guard<std::mutex> lock(mMutex); if (mListed) { return mTraitsList; std::vector<C2Component::Traits> const& Codec2Client::listComponents() const { return Cache::List()[mServiceIndex].getTraits(); } std::vector<C2Component::Traits> Codec2Client::_listComponents( bool* success) const { std::vector<C2Component::Traits> traits; std::string const& serviceName = getServiceName(); Return<void> transStatus = mBase->listComponents( [this](Status s, [&traits, &serviceName](Status s, const hidl_vec<IComponentStore::ComponentTraits>& t) { if (s != Status::OK) { LOG(DEBUG) << "listComponents -- call failed: " LOG(DEBUG) << "_listComponents -- call failed: " << static_cast<c2_status_t>(s) << "."; return; } mTraitsList.resize(t.size()); traits.resize(t.size()); for (size_t i = 0; i < t.size(); ++i) { if (!objcpy(&mTraitsList[i], t[i])) { LOG(ERROR) << "listComponents -- corrupted output."; if (!objcpy(&traits[i], t[i])) { LOG(ERROR) << "_listComponents -- corrupted output."; return; } mTraitsList[i].owner = mServiceName; traits[i].owner = serviceName; } }); if (!transStatus.isOk()) { LOG(ERROR) << "listComponents -- transaction failed."; LOG(ERROR) << "_listComponents -- transaction failed."; *success = false; } else { *success = true; } mListed = true; return mTraitsList; return traits; } c2_status_t Codec2Client::copyBuffer( Loading Loading @@ -649,34 +808,29 @@ std::shared_ptr<C2ParamReflector> }; std::shared_ptr<Codec2Client> Codec2Client::CreateFromService( const char* serviceName, bool waitForService) { if (!serviceName) { return nullptr; } sp<Base> baseStore = waitForService ? Base::getService(serviceName) : Base::tryGetService(serviceName); if (!baseStore) { if (waitForService) { LOG(WARNING) << "Codec2.0 service \"" << serviceName << "\"" " inaccessible. Check the device manifest."; } else { LOG(DEBUG) << "Codec2.0 service \"" << serviceName << "\"" " unavailable at the moment. " " Wait or check the device manifest."; const char* name) { size_t index = getServiceIndex(name); return index == getServiceNames().size() ? nullptr : _CreateFromIndex(index); } return nullptr; } return std::make_shared<Codec2Client>(baseStore, serviceName); std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) { std::string const& name = getServiceNames()[index]; LOG(INFO) << "Creating a Codec2 client to service \"" << name << "\""; sp<Base> baseStore = Base::getService(name); CHECK(baseStore) << "Codec2 service \"" << name << "\"" " inaccessible for unknown reasons."; LOG(INFO) << "Client to Codec2 service \"" << name << "\" created"; return std::make_shared<Codec2Client>(baseStore, index); } c2_status_t Codec2Client::ForAllStores( c2_status_t Codec2Client::ForAllServices( const std::string &key, std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate) { c2_status_t status = C2_NO_INIT; // no IComponentStores present // Cache the mapping key -> index of Codec2Client in getClient(). // Cache the mapping key -> index of Codec2Client in Cache::List(). static std::mutex key2IndexMutex; static std::map<std::string, size_t> key2Index; Loading @@ -684,33 +838,36 @@ c2_status_t Codec2Client::ForAllStores( // the last known client fails, retry once. We do this by pushing the last // known client in front of the list of all clients. std::deque<size_t> indices; for (size_t index = kNumClients; index > 0; ) { for (size_t index = Cache::List().size(); index > 0; ) { indices.push_front(--index); } bool wasMapped = false; std::unique_lock<std::mutex> lock(key2IndexMutex); { std::scoped_lock lock{key2IndexMutex}; auto it = key2Index.find(key); if (it != key2Index.end()) { indices.push_front(it->second); wasMapped = true; } lock.unlock(); } for (size_t index : indices) { std::shared_ptr<Codec2Client> client = getClient(index); Cache& cache = Cache::List()[index]; std::shared_ptr<Codec2Client> client{cache.getClient()}; if (client) { status = predicate(client); if (status == C2_OK) { lock.lock(); std::scoped_lock lock{key2IndexMutex}; key2Index[key] = index; // update last known client index return status; return C2_OK; } } if (wasMapped) { LOG(INFO) << "Could not find \"" << key << "\"" " in the last instance. Retrying..."; wasMapped = false; cache.invalidate(); } } return status; // return the last status from a valid client Loading @@ -722,7 +879,7 @@ std::shared_ptr<Codec2Client::Component> const std::shared_ptr<Listener>& listener, std::shared_ptr<Codec2Client>* owner) { std::shared_ptr<Component> component; c2_status_t status = ForAllStores( c2_status_t status = ForAllServices( componentName, [owner, &component, componentName, &listener]( const std::shared_ptr<Codec2Client> &client) Loading Loading @@ -755,7 +912,7 @@ std::shared_ptr<Codec2Client::Interface> const char* interfaceName, std::shared_ptr<Codec2Client>* owner) { std::shared_ptr<Interface> interface; c2_status_t status = ForAllStores( c2_status_t status = ForAllServices( interfaceName, [owner, &interface, interfaceName]( const std::shared_ptr<Codec2Client> &client) Loading @@ -782,50 +939,54 @@ std::shared_ptr<Codec2Client::Interface> return interface; } std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface() { uint32_t serviceMask = ::android::base::GetUintProperty( "debug.stagefright.c2inputsurface", uint32_t(0)); for (size_t i = 0; i < kNumClients; ++i) { if ((1 << i) & serviceMask) { std::shared_ptr<Codec2Client> client = getClient(i); std::shared_ptr<Codec2Client::InputSurface> inputSurface; if (client && client->createInputSurface(&inputSurface) == C2_OK && inputSurface) { return inputSurface; } std::vector<C2Component::Traits> const& Codec2Client::ListComponents() { static std::vector<C2Component::Traits> sList{[]() { std::vector<C2Component::Traits> list; for (Cache& cache : Cache::List()) { std::vector<C2Component::Traits> const& traits = cache.getTraits(); list.insert(list.end(), traits.begin(), traits.end()); } return list; }()}; return sList; } LOG(INFO) << "Could not create an input surface " "from any Codec2.0 services."; std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface( char const* serviceName) { uint32_t inputSurfaceSetting = ::android::base::GetUintProperty( "debug.stagefright.c2inputsurface", uint32_t(0)); if (inputSurfaceSetting == 0) { return nullptr; } size_t index = getServiceNames().size(); if (serviceName) { index = getServiceIndex(serviceName); if (index == getServiceNames().size()) { LOG(DEBUG) << "CreateInputSurface -- invalid service name: \"" << serviceName << "\""; } } const std::vector<C2Component::Traits>& Codec2Client::ListComponents() { static std::vector<C2Component::Traits> traitsList = [](){ std::vector<C2Component::Traits> list; size_t listSize = 0; ClientList clientList = getClientList(); for (const std::shared_ptr<Codec2Client>& client : clientList) { if (!client) { continue; std::shared_ptr<Codec2Client::InputSurface> inputSurface; if (index != getServiceNames().size()) { std::shared_ptr<Codec2Client> client = Cache::List()[index].getClient(); if (client->createInputSurface(&inputSurface) == C2_OK) { return inputSurface; } listSize += client->listComponents().size(); } list.reserve(listSize); for (const std::shared_ptr<Codec2Client>& client : clientList) { if (!client) { continue; LOG(INFO) << "CreateInputSurface -- attempting to create an input surface " "from all services..."; for (Cache& cache : Cache::List()) { std::shared_ptr<Codec2Client> client = cache.getClient(); if (client->createInputSurface(&inputSurface) == C2_OK) { LOG(INFO) << "CreateInputSurface -- input surface obtained from " "service \"" << client->getServiceName() << "\""; return inputSurface; } list.insert( list.end(), client->listComponents().begin(), client->listComponents().end()); } return list; }(); return traitsList; LOG(WARNING) << "CreateInputSurface -- failed to create an input surface " "from all services"; return nullptr; } // Codec2Client::Listener Loading media/codec2/hidl/client/include/codec2/hidl/client.h +25 −21 Original line number Diff line number Diff line Loading @@ -144,53 +144,52 @@ struct Codec2Client : public Codec2ConfigurableClient { typedef Codec2Client Store; std::string getServiceName() const { return mServiceName; } std::string const& getServiceName() const; c2_status_t createComponent( const C2String& name, const std::shared_ptr<Listener>& listener, C2String const& name, std::shared_ptr<Listener> const& listener, std::shared_ptr<Component>* const component); c2_status_t createInterface( const C2String& name, C2String const& name, std::shared_ptr<Interface>* const interface); c2_status_t createInputSurface( std::shared_ptr<InputSurface>* const inputSurface); const std::vector<C2Component::Traits>& listComponents() const; std::vector<C2Component::Traits> const& listComponents() const; c2_status_t copyBuffer( const std::shared_ptr<C2Buffer>& src, const std::shared_ptr<C2Buffer>& dst); std::shared_ptr<C2Buffer> const& src, std::shared_ptr<C2Buffer> const& dst); std::shared_ptr<C2ParamReflector> getParamReflector(); static std::shared_ptr<Codec2Client> CreateFromService( const char* serviceName, bool waitForService = true); static std::shared_ptr<Codec2Client> CreateFromService(char const* name); // Try to create a component with a given name from all known // IComponentStore services. static std::shared_ptr<Component> CreateComponentByName( const char* componentName, const std::shared_ptr<Listener>& listener, char const* componentName, std::shared_ptr<Listener> const& listener, std::shared_ptr<Codec2Client>* owner = nullptr); // Try to create a component interface with a given name from all known // IComponentStore services. static std::shared_ptr<Interface> CreateInterfaceByName( const char* interfaceName, char const* interfaceName, std::shared_ptr<Codec2Client>* owner = nullptr); // List traits from all known IComponentStore services. static const std::vector<C2Component::Traits>& ListComponents(); static std::vector<C2Component::Traits> const& ListComponents(); // Create an input surface. static std::shared_ptr<InputSurface> CreateInputSurface(); static std::shared_ptr<InputSurface> CreateInputSurface( char const* serviceName = nullptr); // base cannot be null. Codec2Client(const sp<Base>& base, std::string serviceName); Codec2Client(sp<Base> const& base, size_t serviceIndex); protected: sp<Base> mBase; Loading @@ -198,17 +197,22 @@ protected: // Finds the first store where the predicate returns OK, and returns the last // predicate result. Uses key to remember the last store found, and if cached, // it tries that store before trying all stores (one retry). static c2_status_t ForAllStores( static c2_status_t ForAllServices( const std::string& key, std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate); std::function<c2_status_t(std::shared_ptr<Codec2Client> const&)> predicate); mutable std::mutex mMutex; mutable bool mListed; std::string mServiceName; size_t mServiceIndex; mutable std::vector<C2Component::Traits> mTraitsList; sp<::android::hardware::media::bufferpool::V2_0::IClientManager> mHostPoolManager; static std::shared_ptr<Codec2Client> _CreateFromIndex(size_t index); std::vector<C2Component::Traits> _listComponents(bool* success) const; class Cache; }; struct Codec2Client::Interface : public Codec2Client::Configurable { Loading media/codec2/sfplugin/CCodec.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -600,7 +600,7 @@ void CCodec::allocate(const sp<MediaCodecInfo> &codecInfo) { std::shared_ptr<Codec2Client> client; // set up preferred component store to access vendor store parameters client = Codec2Client::CreateFromService("default", false); client = Codec2Client::CreateFromService("default"); if (client) { ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str()); SetPreferredCodec2ComponentStore( Loading Loading
media/codec2/hidl/client/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -30,8 +30,8 @@ cc_library { ], export_shared_lib_headers: [ "libcodec2_hidl@1.0", "libcodec2", "libcodec2_hidl@1.0", ], } Loading
media/codec2/hidl/client/client.cpp +272 −111 Original line number Diff line number Diff line Loading @@ -21,8 +21,12 @@ #include <codec2/hidl/client.h> #include <deque> #include <iterator> #include <limits> #include <map> #include <mutex> #include <sstream> #include <thread> #include <type_traits> #include <vector> Loading @@ -39,6 +43,7 @@ #include <android/hardware/media/c2/1.0/IComponentListener.h> #include <android/hardware/media/c2/1.0/IComponentStore.h> #include <android/hardware/media/c2/1.0/IConfigurable.h> #include <android/hidl/manager/1.2/IServiceManager.h> #include <C2Debug.h> #include <C2BufferPriv.h> Loading Loading @@ -70,35 +75,181 @@ namespace /* unnamed */ { // c2_status_t value that corresponds to hwbinder transaction failure. constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED; // List of known IComponentStore services in the decreasing order of preference. constexpr const char* kClientNames[] = { "default", "software", }; // Number of known IComponentStore services. constexpr size_t kNumClients = std::extent<decltype(kClientNames)>::value; typedef std::array<std::shared_ptr<Codec2Client>, kNumClients> ClientList; // Returns the list of IComponentStore service names that are available on the // device. This list is specified at the build time in manifest files. // Note: A software service will have "_software" as a suffix. std::vector<std::string> const& getServiceNames() { static std::vector<std::string> sServiceNames{[]() { using ::android::hardware::media::c2::V1_0::IComponentStore; using ::android::hidl::manager::V1_2::IServiceManager; while (true) { sp<IServiceManager> serviceManager = IServiceManager::getService(); CHECK(serviceManager) << "Hardware service manager is not running."; // There are three categories of services based on names. std::vector<std::string> defaultNames; // Prefixed with "default" std::vector<std::string> vendorNames; // Prefixed with "vendor" std::vector<std::string> otherNames; // Others Return<void> transResult; transResult = serviceManager->listManifestByInterface( IComponentStore::descriptor, [&defaultNames, &vendorNames, &otherNames]( hidl_vec<hidl_string> const& instanceNames) { for (hidl_string const& instanceName : instanceNames) { char const* name = instanceName.c_str(); if (strncmp(name, "default", 7) == 0) { defaultNames.emplace_back(name); } else if (strncmp(name, "vendor", 6) == 0) { vendorNames.emplace_back(name); } else { otherNames.emplace_back(name); } } }); if (transResult.isOk()) { // Sort service names in each category. std::sort(defaultNames.begin(), defaultNames.end()); std::sort(vendorNames.begin(), vendorNames.end()); std::sort(otherNames.begin(), otherNames.end()); // Concatenate the three lists in this order: default, vendor, // other. std::vector<std::string>& names = defaultNames; names.reserve(names.size() + vendorNames.size() + otherNames.size()); names.insert(names.end(), std::make_move_iterator(vendorNames.begin()), std::make_move_iterator(vendorNames.end())); names.insert(names.end(), std::make_move_iterator(otherNames.begin()), std::make_move_iterator(otherNames.end())); // Summarize to logcat. if (names.empty()) { LOG(INFO) << "No Codec2 services declared in the manifest."; } else { std::stringstream stringOutput; stringOutput << "Available Codec2 services:"; for (std::string const& name : names) { stringOutput << " \"" << name << "\""; } LOG(INFO) << stringOutput.str(); } // Convenience methods to obtain known clients. std::shared_ptr<Codec2Client> getClient(size_t index) { uint32_t serviceMask = ::android::base::GetUintProperty( "debug.media.codec2", uint32_t(0)); return Codec2Client::CreateFromService( kClientNames[index], (serviceMask & (1 << index)) != 0); return names; } LOG(ERROR) << "Could not retrieve the list of service instances of " << IComponentStore::descriptor << ". Retrying..."; } }()}; return sServiceNames; } ClientList getClientList() { ClientList list; for (size_t i = 0; i < list.size(); ++i) { list[i] = getClient(i); // Searches for a name in getServiceNames() and returns the index found. If the // name is not found, the returned index will be equal to // getServiceNames().size(). size_t getServiceIndex(char const* name) { std::vector<std::string> const& names = getServiceNames(); size_t i = 0; for (; i < names.size(); ++i) { if (name == names[i]) { break; } } return i; } } // unnamed namespace // This class caches a Codec2Client object and its component traits. The client // will be created the first time it is needed, and it can be refreshed if the // service dies (by calling invalidate()). The first time listComponents() is // called from the client, the result will be cached. class Codec2Client::Cache { // Cached client std::shared_ptr<Codec2Client> mClient; mutable std::mutex mClientMutex; // Cached component traits std::vector<C2Component::Traits> mTraits; std::once_flag mTraitsInitializationFlag; // The index of the service. This is based on getServiceNames(). size_t mIndex; // A "valid" cache object must have its mIndex set with init(). bool mValid{false}; // Called by s() exactly once to initialize the cache. The index must be a // valid index into the vector returned by getServiceNames(). Calling // init(index) will associate the cache to the service with name // getServiceNames()[index]. void init(size_t index) { mIndex = index; mValid = true; } public: Cache() = default; // Initializes mClient if needed, then returns mClient. // If the service is unavailable but listed in the manifest, this function // will block indefinitely. std::shared_ptr<Codec2Client> getClient() { CHECK(mValid) << "Uninitialized cache"; std::scoped_lock lock{mClientMutex}; if (!mClient) { mClient = Codec2Client::_CreateFromIndex(mIndex); } return mClient; } // Causes a subsequent call to getClient() to create a new client. This // function should be called after the service dies. // // Note: This function is called only by ForAllServices(). void invalidate() { CHECK(mValid) << "Uninitialized cache"; std::scoped_lock lock{mClientMutex}; mClient = nullptr; } // Returns a list of traits for components supported by the service. This // list is cached. std::vector<C2Component::Traits> const& getTraits() { CHECK(mValid) << "Uninitialized cache"; std::call_once(mTraitsInitializationFlag, [this]() { bool success{false}; // Spin until _listComponents() is successful. while (true) { std::shared_ptr<Codec2Client> client = getClient(); mTraits = client->_listComponents(&success); if (success) { break; } using namespace std::chrono_literals; static constexpr auto kServiceRetryPeriod = 5s; LOG(INFO) << "Failed to retrieve component traits from service " "\"" << getServiceNames()[mIndex] << "\". " "Retrying..."; std::this_thread::sleep_for(kServiceRetryPeriod); } return list; }); return mTraits; } } // unnamed // List() returns the list of all caches. static std::vector<Cache>& List() { static std::vector<Cache> sCaches{[]() { size_t numServices = getServiceNames().size(); std::vector<Cache> caches(numServices); for (size_t i = 0; i < numServices; ++i) { caches[i].init(i); } return caches; }()}; return sCaches; } }; // Codec2ConfigurableClient Loading Loading @@ -439,7 +590,7 @@ struct Codec2Client::Component::HidlListener : public IComponentListener { // Codec2Client Codec2Client::Codec2Client(const sp<IComponentStore>& base, std::string serviceName) size_t serviceIndex) : Configurable{ [base]() -> sp<IConfigurable> { Return<sp<IConfigurable>> transResult = Loading @@ -450,8 +601,7 @@ Codec2Client::Codec2Client(const sp<IComponentStore>& base, }() }, mBase{base}, mListed{false}, mServiceName{serviceName} { mServiceIndex{serviceIndex} { Return<sp<IClientManager>> transResult = base->getPoolClientManager(); if (!transResult.isOk()) { LOG(ERROR) << "getPoolClientManager -- transaction failed."; Loading @@ -460,6 +610,10 @@ Codec2Client::Codec2Client(const sp<IComponentStore>& base, } } std::string const& Codec2Client::getServiceName() const { return getServiceNames()[mServiceIndex]; } c2_status_t Codec2Client::createComponent( const C2String& name, const std::shared_ptr<Codec2Client::Listener>& listener, Loading Loading @@ -558,33 +712,38 @@ c2_status_t Codec2Client::createInputSurface( return status; } const std::vector<C2Component::Traits>& Codec2Client::listComponents() const { std::lock_guard<std::mutex> lock(mMutex); if (mListed) { return mTraitsList; std::vector<C2Component::Traits> const& Codec2Client::listComponents() const { return Cache::List()[mServiceIndex].getTraits(); } std::vector<C2Component::Traits> Codec2Client::_listComponents( bool* success) const { std::vector<C2Component::Traits> traits; std::string const& serviceName = getServiceName(); Return<void> transStatus = mBase->listComponents( [this](Status s, [&traits, &serviceName](Status s, const hidl_vec<IComponentStore::ComponentTraits>& t) { if (s != Status::OK) { LOG(DEBUG) << "listComponents -- call failed: " LOG(DEBUG) << "_listComponents -- call failed: " << static_cast<c2_status_t>(s) << "."; return; } mTraitsList.resize(t.size()); traits.resize(t.size()); for (size_t i = 0; i < t.size(); ++i) { if (!objcpy(&mTraitsList[i], t[i])) { LOG(ERROR) << "listComponents -- corrupted output."; if (!objcpy(&traits[i], t[i])) { LOG(ERROR) << "_listComponents -- corrupted output."; return; } mTraitsList[i].owner = mServiceName; traits[i].owner = serviceName; } }); if (!transStatus.isOk()) { LOG(ERROR) << "listComponents -- transaction failed."; LOG(ERROR) << "_listComponents -- transaction failed."; *success = false; } else { *success = true; } mListed = true; return mTraitsList; return traits; } c2_status_t Codec2Client::copyBuffer( Loading Loading @@ -649,34 +808,29 @@ std::shared_ptr<C2ParamReflector> }; std::shared_ptr<Codec2Client> Codec2Client::CreateFromService( const char* serviceName, bool waitForService) { if (!serviceName) { return nullptr; } sp<Base> baseStore = waitForService ? Base::getService(serviceName) : Base::tryGetService(serviceName); if (!baseStore) { if (waitForService) { LOG(WARNING) << "Codec2.0 service \"" << serviceName << "\"" " inaccessible. Check the device manifest."; } else { LOG(DEBUG) << "Codec2.0 service \"" << serviceName << "\"" " unavailable at the moment. " " Wait or check the device manifest."; const char* name) { size_t index = getServiceIndex(name); return index == getServiceNames().size() ? nullptr : _CreateFromIndex(index); } return nullptr; } return std::make_shared<Codec2Client>(baseStore, serviceName); std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) { std::string const& name = getServiceNames()[index]; LOG(INFO) << "Creating a Codec2 client to service \"" << name << "\""; sp<Base> baseStore = Base::getService(name); CHECK(baseStore) << "Codec2 service \"" << name << "\"" " inaccessible for unknown reasons."; LOG(INFO) << "Client to Codec2 service \"" << name << "\" created"; return std::make_shared<Codec2Client>(baseStore, index); } c2_status_t Codec2Client::ForAllStores( c2_status_t Codec2Client::ForAllServices( const std::string &key, std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate) { c2_status_t status = C2_NO_INIT; // no IComponentStores present // Cache the mapping key -> index of Codec2Client in getClient(). // Cache the mapping key -> index of Codec2Client in Cache::List(). static std::mutex key2IndexMutex; static std::map<std::string, size_t> key2Index; Loading @@ -684,33 +838,36 @@ c2_status_t Codec2Client::ForAllStores( // the last known client fails, retry once. We do this by pushing the last // known client in front of the list of all clients. std::deque<size_t> indices; for (size_t index = kNumClients; index > 0; ) { for (size_t index = Cache::List().size(); index > 0; ) { indices.push_front(--index); } bool wasMapped = false; std::unique_lock<std::mutex> lock(key2IndexMutex); { std::scoped_lock lock{key2IndexMutex}; auto it = key2Index.find(key); if (it != key2Index.end()) { indices.push_front(it->second); wasMapped = true; } lock.unlock(); } for (size_t index : indices) { std::shared_ptr<Codec2Client> client = getClient(index); Cache& cache = Cache::List()[index]; std::shared_ptr<Codec2Client> client{cache.getClient()}; if (client) { status = predicate(client); if (status == C2_OK) { lock.lock(); std::scoped_lock lock{key2IndexMutex}; key2Index[key] = index; // update last known client index return status; return C2_OK; } } if (wasMapped) { LOG(INFO) << "Could not find \"" << key << "\"" " in the last instance. Retrying..."; wasMapped = false; cache.invalidate(); } } return status; // return the last status from a valid client Loading @@ -722,7 +879,7 @@ std::shared_ptr<Codec2Client::Component> const std::shared_ptr<Listener>& listener, std::shared_ptr<Codec2Client>* owner) { std::shared_ptr<Component> component; c2_status_t status = ForAllStores( c2_status_t status = ForAllServices( componentName, [owner, &component, componentName, &listener]( const std::shared_ptr<Codec2Client> &client) Loading Loading @@ -755,7 +912,7 @@ std::shared_ptr<Codec2Client::Interface> const char* interfaceName, std::shared_ptr<Codec2Client>* owner) { std::shared_ptr<Interface> interface; c2_status_t status = ForAllStores( c2_status_t status = ForAllServices( interfaceName, [owner, &interface, interfaceName]( const std::shared_ptr<Codec2Client> &client) Loading @@ -782,50 +939,54 @@ std::shared_ptr<Codec2Client::Interface> return interface; } std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface() { uint32_t serviceMask = ::android::base::GetUintProperty( "debug.stagefright.c2inputsurface", uint32_t(0)); for (size_t i = 0; i < kNumClients; ++i) { if ((1 << i) & serviceMask) { std::shared_ptr<Codec2Client> client = getClient(i); std::shared_ptr<Codec2Client::InputSurface> inputSurface; if (client && client->createInputSurface(&inputSurface) == C2_OK && inputSurface) { return inputSurface; } std::vector<C2Component::Traits> const& Codec2Client::ListComponents() { static std::vector<C2Component::Traits> sList{[]() { std::vector<C2Component::Traits> list; for (Cache& cache : Cache::List()) { std::vector<C2Component::Traits> const& traits = cache.getTraits(); list.insert(list.end(), traits.begin(), traits.end()); } return list; }()}; return sList; } LOG(INFO) << "Could not create an input surface " "from any Codec2.0 services."; std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface( char const* serviceName) { uint32_t inputSurfaceSetting = ::android::base::GetUintProperty( "debug.stagefright.c2inputsurface", uint32_t(0)); if (inputSurfaceSetting == 0) { return nullptr; } size_t index = getServiceNames().size(); if (serviceName) { index = getServiceIndex(serviceName); if (index == getServiceNames().size()) { LOG(DEBUG) << "CreateInputSurface -- invalid service name: \"" << serviceName << "\""; } } const std::vector<C2Component::Traits>& Codec2Client::ListComponents() { static std::vector<C2Component::Traits> traitsList = [](){ std::vector<C2Component::Traits> list; size_t listSize = 0; ClientList clientList = getClientList(); for (const std::shared_ptr<Codec2Client>& client : clientList) { if (!client) { continue; std::shared_ptr<Codec2Client::InputSurface> inputSurface; if (index != getServiceNames().size()) { std::shared_ptr<Codec2Client> client = Cache::List()[index].getClient(); if (client->createInputSurface(&inputSurface) == C2_OK) { return inputSurface; } listSize += client->listComponents().size(); } list.reserve(listSize); for (const std::shared_ptr<Codec2Client>& client : clientList) { if (!client) { continue; LOG(INFO) << "CreateInputSurface -- attempting to create an input surface " "from all services..."; for (Cache& cache : Cache::List()) { std::shared_ptr<Codec2Client> client = cache.getClient(); if (client->createInputSurface(&inputSurface) == C2_OK) { LOG(INFO) << "CreateInputSurface -- input surface obtained from " "service \"" << client->getServiceName() << "\""; return inputSurface; } list.insert( list.end(), client->listComponents().begin(), client->listComponents().end()); } return list; }(); return traitsList; LOG(WARNING) << "CreateInputSurface -- failed to create an input surface " "from all services"; return nullptr; } // Codec2Client::Listener Loading
media/codec2/hidl/client/include/codec2/hidl/client.h +25 −21 Original line number Diff line number Diff line Loading @@ -144,53 +144,52 @@ struct Codec2Client : public Codec2ConfigurableClient { typedef Codec2Client Store; std::string getServiceName() const { return mServiceName; } std::string const& getServiceName() const; c2_status_t createComponent( const C2String& name, const std::shared_ptr<Listener>& listener, C2String const& name, std::shared_ptr<Listener> const& listener, std::shared_ptr<Component>* const component); c2_status_t createInterface( const C2String& name, C2String const& name, std::shared_ptr<Interface>* const interface); c2_status_t createInputSurface( std::shared_ptr<InputSurface>* const inputSurface); const std::vector<C2Component::Traits>& listComponents() const; std::vector<C2Component::Traits> const& listComponents() const; c2_status_t copyBuffer( const std::shared_ptr<C2Buffer>& src, const std::shared_ptr<C2Buffer>& dst); std::shared_ptr<C2Buffer> const& src, std::shared_ptr<C2Buffer> const& dst); std::shared_ptr<C2ParamReflector> getParamReflector(); static std::shared_ptr<Codec2Client> CreateFromService( const char* serviceName, bool waitForService = true); static std::shared_ptr<Codec2Client> CreateFromService(char const* name); // Try to create a component with a given name from all known // IComponentStore services. static std::shared_ptr<Component> CreateComponentByName( const char* componentName, const std::shared_ptr<Listener>& listener, char const* componentName, std::shared_ptr<Listener> const& listener, std::shared_ptr<Codec2Client>* owner = nullptr); // Try to create a component interface with a given name from all known // IComponentStore services. static std::shared_ptr<Interface> CreateInterfaceByName( const char* interfaceName, char const* interfaceName, std::shared_ptr<Codec2Client>* owner = nullptr); // List traits from all known IComponentStore services. static const std::vector<C2Component::Traits>& ListComponents(); static std::vector<C2Component::Traits> const& ListComponents(); // Create an input surface. static std::shared_ptr<InputSurface> CreateInputSurface(); static std::shared_ptr<InputSurface> CreateInputSurface( char const* serviceName = nullptr); // base cannot be null. Codec2Client(const sp<Base>& base, std::string serviceName); Codec2Client(sp<Base> const& base, size_t serviceIndex); protected: sp<Base> mBase; Loading @@ -198,17 +197,22 @@ protected: // Finds the first store where the predicate returns OK, and returns the last // predicate result. Uses key to remember the last store found, and if cached, // it tries that store before trying all stores (one retry). static c2_status_t ForAllStores( static c2_status_t ForAllServices( const std::string& key, std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate); std::function<c2_status_t(std::shared_ptr<Codec2Client> const&)> predicate); mutable std::mutex mMutex; mutable bool mListed; std::string mServiceName; size_t mServiceIndex; mutable std::vector<C2Component::Traits> mTraitsList; sp<::android::hardware::media::bufferpool::V2_0::IClientManager> mHostPoolManager; static std::shared_ptr<Codec2Client> _CreateFromIndex(size_t index); std::vector<C2Component::Traits> _listComponents(bool* success) const; class Cache; }; struct Codec2Client::Interface : public Codec2Client::Configurable { Loading
media/codec2/sfplugin/CCodec.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -600,7 +600,7 @@ void CCodec::allocate(const sp<MediaCodecInfo> &codecInfo) { std::shared_ptr<Codec2Client> client; // set up preferred component store to access vendor store parameters client = Codec2Client::CreateFromService("default", false); client = Codec2Client::CreateFromService("default"); if (client) { ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str()); SetPreferredCodec2ComponentStore( Loading