Merge "NuPlayerRenderer: allow video rendering after flushing audio" into qt-dev
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index 136a497..5c810bb 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -85,6 +85,11 @@
* <p>ACameraManager_getCameraIdList will allocate and return an {@link ACameraIdList}.
* The caller must call {@link ACameraManager_deleteCameraIdList} to free the memory</p>
*
+ * <p>Note: the returned camera list might be a subset to the output of <a href=
+ * "https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getCameraIdList()">
+ * SDK CameraManager#getCameraIdList API</a> as the NDK API does not support some legacy camera
+ * hardware.</p>
+ *
* @param manager the {@link ACameraManager} of interest
* @param cameraIdList the output {@link ACameraIdList} will be filled in here if the method call
* succeeds.
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 9545c45..c395d62 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -1194,7 +1194,8 @@
PREPEND_HEADER_TO_ALL_SYNC,
)
-typedef C2GlobalParam<C2Setting, C2BoolValue, kParamIndexPrependHeaderMode>
+typedef C2GlobalParam<C2Setting, C2SimpleValueStruct<C2Config::prepend_header_mode_t>,
+ kParamIndexPrependHeaderMode>
C2PrependHeaderModeSetting;
constexpr char C2_PARAMKEY_PREPEND_HEADER_MODE[] = "output.buffers.prepend-header";
diff --git a/media/codec2/hidl/client/Android.bp b/media/codec2/hidl/client/Android.bp
index a2a498d..f92d1af 100644
--- a/media/codec2/hidl/client/Android.bp
+++ b/media/codec2/hidl/client/Android.bp
@@ -30,8 +30,8 @@
],
export_shared_lib_headers: [
- "libcodec2_hidl@1.0",
"libcodec2",
+ "libcodec2_hidl@1.0",
],
}
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 0fe8376..53adbbc 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -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>
@@ -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>
@@ -70,35 +75,181 @@
// 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",
- };
+// 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;
-// Number of known IComponentStore services.
-constexpr size_t kNumClients = std::extent<decltype(kClientNames)>::value;
+ while (true) {
+ sp<IServiceManager> serviceManager = IServiceManager::getService();
+ CHECK(serviceManager) << "Hardware service manager is not running.";
-typedef std::array<std::shared_ptr<Codec2Client>, kNumClients> ClientList;
+ // 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());
-// 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);
+ // 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();
+ }
+
+ 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 list;
+ return i;
}
-} // unnamed
+} // 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 mTraits;
+ }
+
+ // 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
@@ -439,7 +590,7 @@
// Codec2Client
Codec2Client::Codec2Client(const sp<IComponentStore>& base,
- std::string serviceName)
+ size_t serviceIndex)
: Configurable{
[base]() -> sp<IConfigurable> {
Return<sp<IConfigurable>> transResult =
@@ -450,8 +601,7 @@
}()
},
mBase{base},
- mListed{false},
- mServiceName{serviceName} {
+ mServiceIndex{serviceIndex} {
Return<sp<IClientManager>> transResult = base->getPoolClientManager();
if (!transResult.isOk()) {
LOG(ERROR) << "getPoolClientManager -- transaction failed.";
@@ -460,6 +610,10 @@
}
}
+std::string const& Codec2Client::getServiceName() const {
+ return getServiceNames()[mServiceIndex];
+}
+
c2_status_t Codec2Client::createComponent(
const C2String& name,
const std::shared_ptr<Codec2Client::Listener>& listener,
@@ -558,33 +712,38 @@
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(
@@ -649,34 +808,29 @@
};
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.";
- }
- return nullptr;
- }
- return std::make_shared<Codec2Client>(baseStore, serviceName);
+ const char* name) {
+ size_t index = getServiceIndex(name);
+ return index == getServiceNames().size() ?
+ nullptr : _CreateFromIndex(index);
}
-c2_status_t Codec2Client::ForAllStores(
+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::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;
@@ -684,33 +838,36 @@
// 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);
- auto it = key2Index.find(key);
- if (it != key2Index.end()) {
- indices.push_front(it->second);
- wasMapped = true;
+ {
+ 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
@@ -722,7 +879,7 @@
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)
@@ -755,7 +912,7 @@
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)
@@ -782,50 +939,54 @@
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;
- }
- }
- }
- LOG(INFO) << "Could not create an input surface "
- "from any Codec2.0 services.";
- return nullptr;
-}
-
-const std::vector<C2Component::Traits>& Codec2Client::ListComponents() {
- static std::vector<C2Component::Traits> traitsList = [](){
+std::vector<C2Component::Traits> const& Codec2Client::ListComponents() {
+ static std::vector<C2Component::Traits> sList{[]() {
std::vector<C2Component::Traits> list;
- size_t listSize = 0;
- ClientList clientList = getClientList();
- for (const std::shared_ptr<Codec2Client>& client : clientList) {
- if (!client) {
- continue;
- }
- listSize += client->listComponents().size();
- }
- list.reserve(listSize);
- for (const std::shared_ptr<Codec2Client>& client : clientList) {
- if (!client) {
- continue;
- }
- list.insert(
- list.end(),
- client->listComponents().begin(),
- client->listComponents().end());
+ 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;
+}
- return traitsList;
+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 << "\"";
+ }
+ }
+
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+ LOG(WARNING) << "CreateInputSurface -- failed to create an input surface "
+ "from all services";
+ return nullptr;
}
// Codec2Client::Listener
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index cd42205..8265380 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -144,53 +144,52 @@
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;
@@ -198,17 +197,22 @@
// 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 {
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 8474ce8..751c8c5 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -600,7 +600,7 @@
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(
@@ -859,11 +859,12 @@
std::vector<std::unique_ptr<C2Param>> params;
C2StreamUsageTuning::input usage(0u, 0u);
C2StreamMaxBufferSizeInfo::input maxInputSize(0u, 0u);
+ C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
std::initializer_list<C2Param::Index> indices {
};
c2_status_t c2err = comp->query(
- { &usage, &maxInputSize },
+ { &usage, &maxInputSize, &prepend },
indices,
C2_DONT_BLOCK,
¶ms);
@@ -931,6 +932,16 @@
}
}
+ int32_t clientPrepend;
+ if ((config->mDomain & Config::IS_VIDEO)
+ && (config->mDomain & Config::IS_ENCODER)
+ && msg->findInt32(KEY_PREPEND_HEADERS_TO_SYNC_FRAMES, &clientPrepend)
+ && clientPrepend
+ && (!prepend || prepend.value != PREPEND_HEADER_TO_ALL_SYNC)) {
+ ALOGE("Failed to set KEY_PREPEND_HEADERS_TO_SYNC_FRAMES");
+ return BAD_VALUE;
+ }
+
if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) {
// propagate HDR static info to output format for both encoders and decoders
// if component supports this info, we will update from component, but only the raw port,
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index ef02e74..428f032 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -486,19 +486,31 @@
add(ConfigMapper(std::string(KEY_FEATURE_) + FEATURE_SecurePlayback,
C2_PARAMKEY_SECURE_MODE, "value"));
- add(ConfigMapper("prepend-sps-pps-to-idr-frames",
+ add(ConfigMapper(KEY_PREPEND_HEADERS_TO_SYNC_FRAMES,
C2_PARAMKEY_PREPEND_HEADER_MODE, "value")
.limitTo(D::ENCODER & D::VIDEO)
- .withMapper([](C2Value v) -> C2Value {
+ .withMappers([](C2Value v) -> C2Value {
int32_t value;
- if (v.get(&value) && value) {
- return C2Value(C2Config::PREPEND_HEADER_TO_ALL_SYNC);
- } else {
- return C2Value(C2Config::PREPEND_HEADER_TO_NONE);
+ if (v.get(&value)) {
+ return value ? C2Value(C2Config::PREPEND_HEADER_TO_ALL_SYNC)
+ : C2Value(C2Config::PREPEND_HEADER_TO_NONE);
}
+ return C2Value();
+ }, [](C2Value v) -> C2Value {
+ C2Config::prepend_header_mode_t value;
+ using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(value)>::type;
+ if (v.get((C2ValueType *)&value)) {
+ switch (value) {
+ case C2Config::PREPEND_HEADER_TO_NONE: return 0;
+ case C2Config::PREPEND_HEADER_TO_ALL_SYNC: return 1;
+ case C2Config::PREPEND_HEADER_ON_CHANGE: [[fallthrough]];
+ default: return C2Value();
+ }
+ }
+ return C2Value();
}));
// remove when codecs switch to PARAMKEY
- deprecated(ConfigMapper("prepend-sps-pps-to-idr-frames",
+ deprecated(ConfigMapper(KEY_PREPEND_HEADERS_TO_SYNC_FRAMES,
"coding.add-csd-to-sync-frames", "value")
.limitTo(D::ENCODER & D::VIDEO));
// convert to timestamp base
diff --git a/media/libaudioprocessing/AudioResamplerDyn.cpp b/media/libaudioprocessing/AudioResamplerDyn.cpp
index 0a389bb..ec56b00 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.cpp
+++ b/media/libaudioprocessing/AudioResamplerDyn.cpp
@@ -201,6 +201,8 @@
"ro.audio.resampler.psd.stopband", mPropertyStopbandAttenuation);
mPropertyCutoffPercent = property_get_int32(
"ro.audio.resampler.psd.cutoff_percent", mPropertyCutoffPercent);
+ mPropertyTransitionBandwidthCheat = property_get_int32(
+ "ro.audio.resampler.psd.tbwcheat", mPropertyTransitionBandwidthCheat);
}
template<typename TC, typename TI, typename TO>
@@ -379,9 +381,17 @@
halfLength = mPropertyHalfFilterLength;
stopBandAtten = mPropertyStopbandAttenuation;
useS32 = true;
- fcr = mInSampleRate <= mSampleRate
- ? 0.5 : 0.5 * mSampleRate / mInSampleRate;
- fcr *= mPropertyCutoffPercent / 100.;
+
+ // Use either the stopband location for design (tbwCheat)
+ // or use the 3dB cutoff location for design (fcr).
+ // This choice is exclusive and based on whether fcr > 0.
+ if (mPropertyTransitionBandwidthCheat != 0) {
+ tbwCheat = mPropertyTransitionBandwidthCheat / 100.;
+ } else {
+ fcr = mInSampleRate <= mSampleRate
+ ? 0.5 : 0.5 * mSampleRate / mInSampleRate;
+ fcr *= mPropertyCutoffPercent / 100.;
+ }
} else {
// Voice quality devices have lower sampling rates
// (and may be a consequence of downstream AMR-WB / G.722 codecs).
diff --git a/media/libaudioprocessing/AudioResamplerDyn.h b/media/libaudioprocessing/AudioResamplerDyn.h
index 479142e..82b9505 100644
--- a/media/libaudioprocessing/AudioResamplerDyn.h
+++ b/media/libaudioprocessing/AudioResamplerDyn.h
@@ -193,6 +193,13 @@
int32_t mPropertyCutoffPercent = 100;
// "ro.audio.resampler.psd.cutoff_percent"
+ // Specify the transition bandwidth extension beyond Nyquist.
+ // If this is nonzero then mPropertyCutoffPercent is ignored.
+ // A value of 100 or greater is typically used, where 100 means the
+ // stopband is at Nyquist (this is a typical design).
+ int32_t mPropertyTransitionBandwidthCheat = 0;
+ // "ro.audio.resampler.psd.tbwcheat"
+
// Filter creation design parameters, see setSampleRate()
double mStopbandAttenuationDb = 0.;
double mPassbandRippleDb = 0.;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index cf1a6f1..d8de103 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1776,7 +1776,7 @@
}
int32_t prependSPSPPS = 0;
- if (encoder
+ if (encoder && mIsVideo
&& msg->findInt32("prepend-sps-pps-to-idr-frames", &prependSPSPPS)
&& prependSPSPPS != 0) {
OMX_INDEXTYPE index;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 8b6944b..c84614a 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -783,6 +783,7 @@
constexpr char KEY_OPERATING_RATE[] = "operating-rate";
constexpr char KEY_OUTPUT_REORDER_DEPTH[] = "output-reorder-depth";
constexpr char KEY_PCM_ENCODING[] = "pcm-encoding";
+constexpr char KEY_PREPEND_HEADERS_TO_SYNC_FRAMES[] = "prepend-sps-pps-to-idr-frames";
constexpr char KEY_PRIORITY[] = "priority";
constexpr char KEY_PROFILE[] = "profile";
constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index d6789a4..09638d0 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -120,8 +120,8 @@
std::vector<std::string> providerDeviceIds = provider->mUniqueAPI1CompatibleCameraIds;
// API1 app doesn't handle logical and physical camera devices well. So
- // for each [logical, physical1, physical2, ...] id combo, only take the
- // first id advertised by HAL, and filter out the rest.
+ // for each camera facing, only take the first id advertised by HAL in
+ // all [logical, physical1, physical2, ...] id combos, and filter out the rest.
filterLogicalCameraIdsLocked(providerDeviceIds);
deviceIds.insert(deviceIds.end(), providerDeviceIds.begin(), providerDeviceIds.end());
@@ -2500,8 +2500,11 @@
void CameraProviderManager::filterLogicalCameraIdsLocked(
std::vector<std::string>& deviceIds) const
{
- std::unordered_set<std::string> removedIds;
+ // Map between camera facing and camera IDs related to logical camera.
+ std::map<int, std::unordered_set<std::string>> idCombos;
+ // Collect all logical and its underlying physical camera IDs for each
+ // facing.
for (auto& deviceId : deviceIds) {
auto deviceInfo = findDeviceInfoLocked(deviceId);
if (deviceInfo == nullptr) continue;
@@ -2509,25 +2512,38 @@
if (!deviceInfo->mIsLogicalCamera) {
continue;
}
- // idCombo contains the ids of a logical camera and its physical cameras
- std::vector<std::string> idCombo = deviceInfo->mPhysicalIds;
- idCombo.push_back(deviceId);
+ // combo contains the ids of a logical camera and its physical cameras
+ std::vector<std::string> combo = deviceInfo->mPhysicalIds;
+ combo.push_back(deviceId);
+
+ hardware::CameraInfo info;
+ status_t res = deviceInfo->getCameraInfo(&info);
+ if (res != OK) {
+ ALOGE("%s: Error reading camera info: %s (%d)", __FUNCTION__, strerror(-res), res);
+ continue;
+ }
+ idCombos[info.facing].insert(combo.begin(), combo.end());
+ }
+
+ // Only expose one camera ID per facing for all logical and underlying
+ // physical camera IDs.
+ for (auto& r : idCombos) {
+ auto& removedIds = r.second;
for (auto& id : deviceIds) {
- auto foundId = std::find(idCombo.begin(), idCombo.end(), id);
- if (foundId == idCombo.end()) {
+ auto foundId = std::find(removedIds.begin(), removedIds.end(), id);
+ if (foundId == removedIds.end()) {
continue;
}
- idCombo.erase(foundId);
- removedIds.insert(idCombo.begin(), idCombo.end());
+ removedIds.erase(foundId);
break;
}
+ deviceIds.erase(std::remove_if(deviceIds.begin(), deviceIds.end(),
+ [&removedIds](const std::string& s) {
+ return removedIds.find(s) != removedIds.end();}),
+ deviceIds.end());
}
-
- deviceIds.erase(std::remove_if(deviceIds.begin(), deviceIds.end(),
- [&removedIds](const std::string& s) {return removedIds.find(s) != removedIds.end();}),
- deviceIds.end());
}
} // namespace android